[leetcode javascript]9.6-9.13做过的题目:1002,242,1160,203,160,1078,234,876,922,1030

突然意识到leetcode是不存自己写的代码的,都是临时存在本地而已,如果自己清理垃圾,估计会直接被清除掉。但自己的一些想法会写在代码里,还是把代码搬了过了。有想过弄去github的,但是感觉这里会方便一点,先弄在这里吧。

以下是9.6-9.13做过的题目

目录

1002. 查找常用字符

 242. 有效的字母异位词

1160. 拼写单词

203. 移除链表元素

160. 相交链表 

1078. Bigram 分词

234. 回文链表

876. 链表的中间结点

922. 按奇偶排序数组 II

1030. 距离顺序排列矩阵单元格


1002. 查找常用字符

给定仅有小写字母组成的字符串数组 A,返回列表中的每个字符串中都显示的全部字符(包括重复字符)组成的列表。例如,如果一个字符在每个字符串中出现 3 次,但不是 4 次,则需要在最终答案中包含该字符 3 次。

你可以按任意顺序返回答案。

示例 1:

输入:["bella","label","roller"]
输出:["e","l","l"]
示例 2:

输入:["cool","lock","cook"]
输出:["c","o"]

题解:https://leetcode-cn.com/problems/find-common-characters/solution/js-by-blzbanme/

这题的解法三用了filter,不太懂。filter会返回return true的元素组成的数组,但下面这行代码,实在巧妙,我有点暂时接受不了。我的疑问是,temp[index] = 1这个,也算true的表达??

 return index !== -1 ? temp[index] = 1 : false;
/**
 * @param {string[]} A
 * @return {string[]}
 */
var commonChars = function(A) {
    let res = A[0].split("");
    for(let i = 1; i < A.length; i++){
        let temp = A[i].split("");
        res = res.filter(e => {
            let index = temp.indexOf(e);
            return index !== -1 ? temp[index] = 1 : false;
        });
    }
    return res;
};

 242. 有效的字母异位词

 

给定两个字符串 s 和 t ,编写一个函数来判断 t 是否是 s 的字母异位词。

示例 1:

输入: s = "anagram", t = "nagaram"
输出: true
示例 2:

输入: s = "rat", t = "car"
输出: false

/**
 * @param {string} s
 * @param {string} t
 * @return {boolean}
 */
var isAnagram = function(s, t) {
    let res = s.split("");
    let temp = t.split("");
    if(res.length !== temp.length)return false;//这句话还是非常有用的。直接为后面不管是用哈希还是其他都省去不少麻烦
    return res.every(e => {
        let index = temp.indexOf(e);
        return index !== -1? temp[index] = 1 : false;
    });
};

上面那个是我自己用的方法,跟1002那道题一样,为什么那道题运行速度还行而这个运行速度直接飙2000ms?

其他人的解法:https://leetcode-cn.com/problems/valid-anagram/solution/you-xiao-de-zi-mu-yi-wei-ci-by-chitanda-eru/
1.是用哈希表,记录次数。如果第一次记录则将次数设为1,若本身已有次数,则在其基础上+1。记录完次数时候,比较s和t的哈希表
let char in对象的话,char表示的是属性。
2.用sort排序完之后一一匹配,但有一个类似的更简便的是:(这个甚至不出现for这一个词。用等号就实现了)牛

var isAnagram = function(s, t) {
     if(s.length != t.length) return false;
     return  s.split('').sort().join('') == t.split('').sort().join('');
 }

1160. 拼写单词

1.get的用法:返回根据键值检索到的特定的值
2.let newMap = new Map(map);//复制一个map
3.这题可多看

给你一份『词汇表』(字符串数组) words 和一张『字母表』(字符串) chars。

假如你可以用 chars 中的『字母』(字符)拼写出 words 中的某个『单词』(字符串),那么我们就认为你掌握了这个单词。

注意:每次拼写时,chars 中的每个字母都只能用一次。

返回词汇表 words 中你掌握的所有单词的 长度之和。

示例 1:

输入:words = ["cat","bt","hat","tree"], chars = "atach"
输出:6
解释: 
可以形成字符串 "cat" 和 "hat",所以答案是 3 + 3 = 6。
示例 2:

输入:words = ["hello","world","leetcode"], chars = "welldonehoneyr"
输出:10
解释:
可以形成字符串 "hello" 和 "world",所以答案是 5 + 5 = 10。

/**
 * @param {string[]} words
 * @param {string} chars
 * @return {number}
 */
var countCharacters = function(words, chars) {
    let map = new Map();
    
    for(let c of chars){
        if(map.has(c))
            map.set(c, map.get(c)+1);//get:返回根据键值检索到的特定的值
        else
            map.set(c, 1);
    }
    
    let res = 0;
    for(let w of words){
        let temp = w.split('');//将一个单词拆分成一个个字母储存
        if(check(temp,map))
            res += temp.length;
    }
    return res;
    
    function check(word, map){//word是存着单词的数组,map是存着单词和它对应的出现次数的哈希表
        let newMap = new Map(map);//复制一个map
        let back = true;
        for(let w of word){
            if(newMap.has(w) && newMap.get(w) > 0)
                newMap.set(w, newMap.get(w)-1);
            else
                back = false;
        }
        return back;
    }
};

203. 移除链表元素

删除链表中等于给定值 val 的所有节点。

示例:

输入: 1->2->6->3->4->5->6, val = 6
输出: 1->2->3->4->5

19.9.11
while中的head && head.next是有顺序的。head要在head.next前面。不然,如果head为空,那head.next就会出错。

我!一开始以为这道题很简单的...没想到后面一直改bug,例子能通过这个就通不过那个,为了结果改代码,改到我自己都不认得了...

/**
 * Definition for singly-linked list.
 * function ListNode(val) {
 *     this.val = val;
 *     this.next = null;
 * }
 */
/**
 * @param {ListNode} head
 * @param {number} val
 * @return {ListNode}
 */
// 自己写的,放弃了放弃了
var removeElements = function(head, val) {
    let apple = head;
    while(head){
        if(head.next === null){
            if(head.val === val){
                head = null;
                return head;
            }
            head = head.next;
        }
        else{
            while(head && head.next){
                if(head.next.val === val){
                    head.next = head.next.next;                
                }
                if(head.next === null)break;
                head = head.next;           //估计我的代码一开始就从这里错掉了
            }
        }
        
    }

    return apple;
};

//方法一
var removeElements = function(head, val) {
    while(head && head.val === val){
        head = head.next; //这是将头结点直接挪到下一个节点上去
    }
    if(!head)return head;
    let pre = head;
    while(pre && pre.next){//需要加pre && 吗。 还是加吧,没影响的情况下自己能更好理解
        if(pre.next.val === val){
            pre.next = pre.next.next;
        }else{
             pre = pre.next;// 首先,不可以去掉原先的else,请看这个栗子[1,2,2,1]2,如果去掉else,在删除完第一个2之后,pre去到了下一个2,它看的是谁?它看的是后面的数了,不再看自己是否要被删掉。
        } 
    }
    return head;
}

// 方法二 额外加一个虚拟节点
var removeElements = function(head, val) {
    let node = new ListNode(val-1);
    node.next = head;
    let pre = node;
    
    while(pre && pre.next){
        if(pre.next.val === val){
            pre.next = pre.next.next;
        }else{
            pre = pre.next;
        }
    }
    return node.next;
}

// 方法三 递归
var removeElements = function(head, val) {
    if(!head)return null;
    head.next = removeElements(head.next, val);
    if(head.val === val){
        return head.next;
    }else{
        return head;
    }
}

160. 相交链表 

/**
 * Definition for singly-linked list.
 * function ListNode(val) {
 *     this.val = val;
 *     this.next = null;
 * }
 */

/**
 * @param {ListNode} headA
 * @param {ListNode} headB
 * @return {ListNode}
 */
// 方法一
var getIntersectionNode = function(headA, headB) {
    let pA = headA;
    let pB = headB;
    
    while(pA !== pB){
        pA = pA? pA.next : headB;
        pB = pB? pB.next : headA;
    }
    return pA;
};


// 先遍历headA并打上标记,再遍历headB寻找标记。
var getIntersectionNode = function(headA, headB) {
    while(headA){
        headA.sep = 1;
        headA = headA.next;
    }
    while(headB){
        if(headB.sep) return headB
        headB = headB.next;
    }
};

1078. Bigram 分词

 给出第一个词 first 和第二个词 second,考虑在某些文本 text 中可能以 "first second third" 形式出现的情况,其中 second 紧随 first 出现,third 紧随 second 出现。

对于每种这样的情况,将第三个词 "third" 添加到答案中,并返回答案。

示例 1:

输入:text = "alice is a good girl she is a good student", first = "a", second = "good"
输出:["girl","student"]

/**
 * @param {string} text
 * @param {string} first
 * @param {string} second
 * @return {string[]}
 */
// 为什么我的for循环里面的if进不去?!!!明明和题解一样啊?!!!  (过了十几分钟终于知道了...开头的split里没有空格
var findOcurrences = function(text, first, second) {
    let textArr = text.split('');
    // let arr = [];
    let result = [];
    // arr.push(first, second);
    // console.log(arr);
    for(let i = 0; i < textArr.length; i++){
        if(textArr[i] == first && textArr[i+1] == second && !!textArr[i+2]){
            console.log('hello');//这个没显示、、、
            result.push(textArr[i+2]);
            console.log(result);
        }
    }
    return result;
};

var findOcurrences = function(text, first, second) {
    let textArr = text.split(' ');
    // let addArr = []
    let result = [];
    // addArr.push(first, second)
    for(let i = 0; i < textArr.length; i++){
        if(textArr[i] == first && textArr[i+1] == second && !!textArr[i+2]){
            // console.log('hello');
            result.push(textArr[i+2]);
        }
    }
    return result;
};

234. 回文链表

请判断一个链表是否为回文链表。

示例 1:

输入: 1->2
输出: false

示例 2:

输入: 1->2->2->1
输出: true
/**
 * Definition for singly-linked list.
 * function ListNode(val) {
 *     this.val = val;
 *     this.next = null;
 * }
 */
/**
 * @param {ListNode} head
 * @return {boolean}
 */
var isPalindrome = function(head) {
    if(!head || !head.next)return true;
    let mid = head,
        pre,//这个初始化加不加 null都没关系
        reversed = null;
    while(head && head.next){
        pre = mid;//这个赋值要在 mid被修改之前
        mid = mid.next;
        head = head.next.next;
        pre.next = reversed;
        reversed = pre;
    }
    if(head)mid = mid.next;//①
    while(mid){
        if(mid.val !== reversed.val)return false;
        mid = mid.next;
        reversed = reversed.next;
    }
    return true;
};

①:这个有点厉害。如果链表是奇数个,那退出while循环时,head指向最后一个。但如果是偶数个时,head会指向null。所以用head的指向来判断链表数是奇数还是偶数。如果是奇数,mid要加1,避开那个对称点


876. 链表的中间结点

给定一个带有头结点 head 的非空单链表,返回链表的中间结点。

如果有两个中间结点,则返回第二个中间结点。

示例 1:

输入:[1,2,3,4,5]
输出:此列表中的结点 3 (序列化形式:[3,4,5])
返回的结点值为 3 。 (测评系统对该结点序列化表述是 [3,4,5])。
注意,我们返回了一个 ListNode 类型的对象 ans,这样:
ans.val = 3, ans.next.val = 4, ans.next.next.val = 5, 以及 ans.next.next.next = NULL.

/**
 * Definition for singly-linked list.
 * function ListNode(val) {
 *     this.val = val;
 *     this.next = null;
 * }
 */
/**
 * @param {ListNode} head
 * @return {ListNode}
 */
//自己的解法...慢的要死  这个还是基于链表的
var middleNode = function(head) {
    let apple = head,
        length = 0,
        result = head,
        len;
    
    for(; apple != null; apple = apple.next){
        length++;
    } 
    if(length % 2 === 0){
        len = length/2;
    }else{
        len = length/2 - 1; //不知道为什么要-1。因为我是根据运行结果来调试的,-1的时候结果对了
    }
    for(let i = 0; i < len ; i++){
        result = result.next;
    }
    return result;
};

//解法1:将链表输出到数组,数组的话可以按索引找  ???怎么return是undefined??因为要求的是返回链表,你现在只是把数存进数组了,应该把val和next同时存进数组的,所以用push才正确
var middleNode = function(head) {
    let result = [];
    for(let i = 0, apple = head; apple != null; i++, apple = apple.next){
        // result[i] = apple.val;//这句话错了
        result.push(apple);
    }
    // console.log(result);
    // console.log(result.length);
    // console.log (result.slice(Math.floor(result.length/2)));
    // return Array.from(result);
    // console.log(5/2);//2.5
    return result[Math.floor(result.length/2)];//注意了!下标直接用result.length/2是不行的,会直接返回undefined,因为目前的测试代码的长度为5,5/2=2.5而下标是没有2.5的,一定要用floor或者trunc方法对数据进行处理
}

// var middleNode = function(head) {
//     let A = [head];
//     while (A[A.length - 1].next != null)
//         A.push(A[A.length - 1].next);
//     return A[Math.trunc(A.length / 2)];
// };

// 解法2 快慢指针 68ms
var middleNode = function(head) {
    let slow = fast = head;
    while(fast && fast.next != null){ //为什么去掉fast 就会报错? 因为一定要检测fast.next是否为空,所以也要检测fast,因为如果fast为空,fast.next是会出错的。
        // console.log(slow.val +" "+fast.val);
        slow = slow.next;
        fast = fast.next.next;//用到fast.next.next,所以要看一下fast.next是否为空,因为如果fast.next为空,fast.next.next是会出错的
    }
    return slow;
}

922. 按奇偶排序数组 II

给定一个非负整数数组 A, A 中一半整数是奇数,一半整数是偶数。

对数组进行排序,以便当 A[i] 为奇数时,i 也是奇数;当 A[i] 为偶数时, i 也是偶数。

你可以返回任何满足上述条件的数组作为答案。

示例:

输入:[4,2,5,7]
输出:[4,5,2,7]
解释:[4,7,2,5],[2,5,4,7],[2,7,4,5] 也会被接受。 

第一版:我觉得要用到splice

**官方题解:**(有点类似快排的一部分,用了双链表)
一旦所有偶数都放在了正确的位置上,那么所有奇数也一定都在正确的位子上。所以只需要关注 A[0], A[2], A[4], ... 都正确就可以了。
将数组分成两个部分,分别是偶数部分 even = A[0], A[2], A[4], ... 和奇数部分 odd = A[1], A[3], A[5], ...。定义两个指针 i 和 j, 每次循环都需要保证偶数部分中下标 i 之前的位置全是偶数,奇数部分中下标 j 之前的位置全是奇数。
**算法**
让偶数部分下标 i 之前的所有数都是偶数。为了实现这个目标,把奇数部分作为暂存区,不断增加指向奇数部分的指针,直到找到一个偶数,然后交换指针 i,j 所指的数。

第二版:最外层的for循环好奇怪。写不出不想要的感觉。一写就会多访问数组外的值。
算是初步改好了,还剩数组调换那里,不想再补了。知道怎么补,但是补了之后代码看起来就会很臃肿。算了,跳坑写第三版

第三版:写完了

/**
 * @param {number[]} A
 * @return {number[]}
 */
// 第一版:自己写的时候卡掉了...
// var sortArrayByParityII = function(A) {
//     let odd = [];
//     A.forEach((item, index) => {
//         if(item % 2 !== 0){
//             odd.push(item);
//             // A.splice(index,1);
//         }
//     });
//     console.log(A);
//     console.log(odd);
// };

// 第二版:只想到快排有一部分相似,但是忽略了它的结束条件。在这道题里,如果按快排的思路,很难写结束条件
// var sortArrayByParityII = function(A) {
//     // console.log(A.length);
//     // console.log(A.length/2);
//     let len = A.length/2;
//     let i = 0, j = 1;//忘了快排具体的了,我是要用i做外循环,j做内循环吗?
//     for(let x = 0; x < A.length/2; x++){
//         while(A[i] % 2 == 0 && A[i+2] !== undefined)i += 2;//突然感觉自己在挖坑然后跳了进去...
//         while(A[j] % 2 == 1 && A[j+2] !== undefined)j += 2;
//         console.log("i:"+i+" "+"j:"+j);
//         [A[i],A[j]]=[A[j],A[i]];//要添加多一些条件,这样就会变得冗杂,失去本来想简洁的初衷了
//         console.log(x +":"+A);
//     }
//     return A;
// }

// 第三版
var sortArrayByParityII = function(A) {
    let i = 0,
        j = 1;
    for(; i < A.length; i += 2){
        if(A[i] % 2 == 0)continue;
        while(A[j] % 2 == 1)j += 2;
        [A[i],A[j]]=[A[j],A[i]];
    }
    return A;
}

1030. 距离顺序排列矩阵单元格

给出 R 行 C 列的矩阵,其中的单元格的整数坐标为 (r, c),满足 0 <= r < R 且 0 <= c < C。

另外,我们在该矩阵中给出了一个坐标为 (r0, c0) 的单元格。

返回矩阵中的所有单元格的坐标,并按到 (r0, c0) 的距离从最小到最大的顺序排,其中,两单元格(r1, c1) 和 (r2, c2) 之间的距离是曼哈顿距离,|r1 - r2| + |c1 - c2|。(你可以按任何满足此条件的顺序返回答案。)

示例 1:

输入:R = 1, C = 2, r0 = 0, c0 = 0
输出:[[0,0],[0,1]]
解释:从 (r0, c0) 到其他单元格的距离为:[0,1]

// 这是参考的代码,比较慢 268ms
var allCellsDistOrder = function(R, C, r0, c0) {
    let result = [];
    
    for(let r = 0; r < R; r++){
        for(let c = 0; c < C; c++){
            let temp = [r,c];
            result.push(temp);
        }
    }
    
    result.sort((a,b) => {
        let ta = Math.abs(a[0] - r0) + Math.abs(a[1] - c0),
            tb = Math.abs(b[0] - r0) + Math.abs(b[1] - c0);
        return ta - tb;
    });
    
    return result;
};

 笔记
1. result是二维数组吗? 怎么声明  **解决:** result为一维数组,定义一个是坐标的变量,然后
2. temp那个是数组来的,可以用temp[0]和temp[1]访问。同理,sort里面的那个函数参数a和b也可以用方括号访问
3. sort()还是不熟:如果想要参数一在参数二之前就返回一个负数。(高程P92

 

你可能感兴趣的:(数据结构)