LeetCode部分刷题笔记!!!JavaScript!!!

详细解说请看视频JS老毕:人人都能看得懂的Leetcode力扣刷题教程合集
边看视频边记录笔记!!!部分题目在视频中无!

文章目录

LeetCode第1题:1. 两数之和

在这里插入图片描述
解法1:时间复杂度为O(n*n) 空间复杂度为O(1)

var twoSum = function(nums, target) {
    //给定一个nums,给定一个target,设定1个空数组用来存放下标
    //let result = [];
    //在nums中遍历,找到和为target的两个数,且这两个数不能为同一个元素,即下标不可相同
    for(let i=0;i<nums.length;i++){
        for(let j=i+1;j<nums.length;j++){
           if(nums[i] + nums[j] == target && i!=j){
               //返回这两个数的下标的数组
               return [i,j];
           }
        }
    }
};

解法2:时间复杂度为O(n) 空间复杂度为O(n)

var twoSum = function(nums,target){
    const map = new Map();
    for(let i = 0;i < nums.length;i++){
        const complement = target - nums[i];
        if(map.has(complement)){
            return [map.get(complement),i];
        }else{
            map.set(nums[i],i);
        }
    }
    return [];
} 

LeetCode第2题:2. 两数相加

在这里插入图片描述
代码:

var addTwoNumbers = function(l1,l2){
    let dummy = new ListNode();
    let curr = dummy;
    let carry = 0;
    while(l1 !==null || l2 !==null){
        let sum = 0;
        if(l1){
            sum += l1.val;
            l1 = l1.next;
        }
        if(l2){
            sum += l2.val;
            l2 = l2.next;
        }
        sum +=carry;
        curr.next = new ListNode(sum % 10);
        carry = Math.floor(sum/10);
        curr = curr.next;
    }
    if(carry>0){
        curr.next = new ListNode(carry);
    }
    return dummy.next;
}

LeetCode第3题:3.无重复字符的最长子串

在这里插入图片描述
思路:

方法:sliding window(滑动窗口算法)

  1.创建一个set
  2.两个指针,第一个指向字符串的开头(j),第二个随着for循环遍历字符串(i)
  3.如果set里没有s(i),说明目前为止还没有重复的字符,把s(i)添加到set里,然后更新最大不重复字符的数量
  4.如果set里有s(i),则从set里开始删除s(i),并且递增j,再检查set里是否有s(i)
  5.重复步骤3和4,直到遍历完整个字符串

代码:

var lengthOfLongestSubstring = function(s){
    const set = new Set();
    let i = 0,j = 0,maxLength = 0;
    if(s.length === 0){
        return 0;
    }
    for(i;i<s.length;i++){
        if(!set.has(s[i])){
            set.add(s[i]);
            maxLength = Math.max(maxLength,set.size)
        }else{
            while(set.has(s[i])){
                set.delete(s[j]);
                j++;
            }
            set.add(s[i]);
        }
    }
    return maxLength;
};

LeetCode第5题:5. 最长回文子串

在这里插入图片描述
思路:

有三种情况:
1.长度小于2,直接返回
2.奇数个,有中间字符
3.偶数个,没有中间字符

 1.如果字符串长度小于2,直接返回字符串
 2.定义两个变量,一个start存储当前找到的最大回文字符串的起始位置,另一个maxLength记录字符串的长度(终止位置就是start+maxLength)
 3.创建一个helper function,判断左边和右边是否越界,同时最左边的字符是否等于最右边的字符。
   如果以上三个条件都满足,则判断是否需要更新回文字符串最大长度及最大字符串的起始位置。然后将left--、right++,继续判断,直到不满足三个条件之一
 4.遍历字符串,每个位置调用helper function两遍,第一遍检查i-1,i+1,第二遍检查i、i+1
  (为什么要检查两遍?答:奇数/偶数)

代码:

var longestPalindrome = function(s){
    if(s.length<2){
        return s;
    }
    let start = 0;
    let maxLength = 1;
    function expandAroundCenter(left,right){
        while(left>=0 && right<s.length && s[left]===s[right]){
            if(right - left + 1 > maxLength){
                maxLength = right - left +1;
                start = left;
            }
            left--;
            right++;
        }
    }
    for(let i=0;i<s.length;i++){
        expandAroundCenter(i-1,i+1);
        expandAroundCenter(i,i+1);
    }
    return s.substring(start,start+maxLength);
};

LeetCode第11题:11. 盛最多水的容器

在这里插入图片描述

/**
 * @param {number[]} height
 * @return {number}
 */
var maxArea = function(height) {
    let left = 0, right = height.length - 1;
    let max = 0;
    while(left < right){
        let maxAll = (right - left) * Math.min(height[left],height[right]);
        if(height[left] <= height[right]){
            left++;
            max = Math.max(max,maxAll);
        }else{
            right--;
            max = Math.max(max,maxAll);
        }
    }
    return max;
};

//简化版
var maxArea = function(height) {
    let left = 0;
    let right = height.length - 1;
    let max = 0;
    while(left < right) {
        let temp = (right - left) * Math.min(height[left], height[right]);
        max = Math.max(temp, max);
        if (height[left] <= height[right]) {
            left++;
        } else {
            right--;
        }
    }
    return max;
};

LeetCode第15题:15. 三数之和

在这里插入图片描述
思路:

1.给数组排序
2.遍历数组,从0遍历到length-2
   为什么?答:防止越界
3.如果当前的数字等于前一个数字,则跳过这个数
   为什么?答:避免重复数组出现
4.如果数字不同,则设置start= i+1,end=length-1,查看i,start,end三个数的和比0大还是小,
  · 如果比0小,start++,
  · 如果比0大,end--
  · 如果等于0,则把这三个数添加到结果里
5.返回结果

代码:

var threeSum = function(nums) {
    const result = [];
    nums.sort((a,b)=>{
      return a-b;
    })
    for(let i=0;i<nums.length-2;i++){
        if(i===0 || nums[i] !== nums[i-1]){
            let start = i+1,end = nums.length-1;
            while(start < end){
                if(nums[i] + nums[start] + nums[end] === 0){
                    resule.push([nums[i],nums[start],nums[end]]);
                    start++;
                    end--;
                    while(start < end && nums[start] === nums[start-1]){
                        start++;
                    }
                    while(start < end && nums[end] === nums[end+1]){
                        end--;
                    }
                }else if(nums[i] + nums[start] + nums[end] < 0){
                    start++;
                }else{
                    end--;
                }
            }
        }
    }
    return result;
};

LeetCode第17题:17. 电话号码的字母组合

在这里插入图片描述
代码:

// dfs,回溯算法
var letterCombinations = function(digits) {
    if (digits.length === 0) return [];
    let res = [];
    const map = {'2': 'abc', '3': 'def', '4': 'ghi', '5': 'jkl', '6': 'mno', '7': 'pqrs', '8': 'tuv', '9': 'wxyz'};
    const dfs = (curStr, i) => {
        if (i > digits.length -1) {
            res.push(curStr);
            return;
        }
        const letters = map[digits[i]]
        for (letter of letters) {
            dfs(curStr + letter, i+1);
        }
    }
    dfs('', 0);
    return res;
};

LeetCode第19题:19. 删除链表的倒数第 N 个结点

在这里插入图片描述
思路:

   1.在第一个结点之前设置一个dummy结点,避免只有一个元素无法操作
   2.设置两个指针,分别为n1,n2,开始都指向dummy
   3.两种方法
                           
     1)将n2结点移动n个距离,然后n1,n2同时向后移,
        当n2移动到最后一个元素即n2.next为null的时候,
        删除当前n1.next即n1.next = n1.next.next
       for(let i=0;i<n;i++){
          n2 = n2.next;
       }
                                   
        while(n2.next !== null){
            n1 = n1.next;
            n2 = n2.next;
        }

    2)将n2结点移动n+1个距离,然后n1,n2同时向后移,
      当n2为null时, 删除当前n1.next即n1.next = n1.next.next
        for(let i=0;i<=n;i++){
            n2 = n2.next;
        }

        while(n2 !== null){
            n1 = n1.next;
            n2 = n2.next;
        }

代码:

var removeNthFromEnd = function(head, n) {
    let dummy = new ListNode();
    dummy.next = head;

    let n1 = dummy;
    let n2 = dummy;

    for(let i=0;i<=n;i++){
        n2 = n2.next;
    }

    while(n2 !== null){
        n1 = n1.next;
        n2 = n2.next;
    }

    n1.next = n1.next.next;
    return dummy.next;
};

LeetCode第20题:20. 有效的括号

在这里插入图片描述
思路:

1.创建一个HashMap,把括号配对放进去
2.创建一个stack(array、栈),for循环遍历字符串,对于每一个字符,如果map里有这个key,那说明它是个左括号,从map里取得相对应的右括号(为什么?),把它push进stack里。否则的话,它就是右括号,需要pop出stack里的第一个字符,然后看它是否等于当前的字符。如果不相符,则返回false
3.循环结束后,如果stack不为空,说明还剩一些左括号没有被闭合,返回false。否则返回true。

代码:

var isValid = function(s) {
    const mappings = new Map();
    mappings.set("(" , ")");
    mappings.set("[" , "]");
    mappings.set("{" , "}");

    const stack = [];
    for(let i=0;i<s.length;i++){
        if(mappings.has(s[i])){
            stack.push(mappings.get(s[i]));
        }else{
            if(stick.pop() !== s[i]){
                return false;
            }
        }
    }

    if(stack.length !== 0){
        return false;
    }

    return true;
};

LeetCode第21题:21. 合并两个有序链表

在这里插入图片描述
代码:

var mergeTwoLists = function(l1, l2) {
    let curr = new ListNode();
    let dummy = curr;

    while(l1 !== null && l2 !== null){
        if(l1.val < l2.val){
            curr.next = l1;
            l1 = l1.next;
        }else{
            curr.next = l2;
            l2 = l2.next;
        }
        curr = curr.next;
    }

    if(l1 !== null){
        curr.next = l1;
    }

    if(l2 !== null){
        curr.next = l2;
    }

    return dummy.next;
};

LeetCode第24题:24. 两两交换链表中的节点

在这里插入图片描述
思路:

  1. n1 = p.next;
  2. n2 = p.next.next;
  3. p.next = n2;
  4. n1.next = n2.next;
  5. n2.next = n1;
  6. p = n1;

代码:

var swapPairs = function(head) {
    let dummy = new ListNode();
    dummy.next = head;
    let current = dummy;
    // n1,n2均不为0
    while(current.next !== null && current.next.next !== null){
        let n1 = current.next;
        let n2 = current.next.next;
        current.next = n2;
        n1.next = n2.next;
        n2.next = n1;
        current = n1;
    }
    return dummy.next;
};

LeetCode第49题:49. 字母异位词分组

在这里插入图片描述
思路:

1.检查是否为空数组
2.建立一个长度为26的数组,起始值为0
3.遍历所有字符串,将字符出现的频率放到数组的对应位置里(ASCII)
4.遍历数组,按照相同字母出现频率表进行分组归类(hashMap)
5.遍历map,将结果返回

纠错:join里面的分隔符改成别的例如 . -

测试用例如果是【bdddddddddd, bbbbbbbbbbc】的话key会相同 会报错

0, 1, 0, 10, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0

010100000000000000000000000

0, 10, 1, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0

010100000000000000000000000
Map(1) {
010100000000000000000000000 = 【 bdddddddddd, bbbbbbbbbbc 】
}

代码:

var groupAnagrams = function(strs) {
    if(strs.length === 0){
        return [];
    }

    const map = new Map();

    for(const str of strs){
        const characters = Array(26).fill(0);
        for(let i=0;i<str.length;i++){
            //console.log(str[i]);   
            const ascii = str.charCodeAt(i) - 97;
            //console.log(str.charCodeAt(i));
            //console.log(ascii);
            characters[ascii]++;
        }
        //const key = characters.join("");
        const key = characters.join(".");
        if(map.has(key)){
            //map.set(key,map.get(key.push(str)))
            map.set(key,[...map.get(key),str]);
        }else{
            map.set(key,[str]);
        }
    }

    const result = [];
    for(const arr of map){
        result.push(arr[1]);    // 0是键,1是键值
    }

    return result;
};

LeetCode第53题:53. 最大子序和

在这里插入图片描述
思路:

两次判断:
1.将新的数加入到前面的数组中,还是舍弃之前的数组新开一个数组
2.判断最大值

代码:

var maxSubArray = function(nums) {
    const memo = [];
    memo[0] = nums[0];

    for(let i=1;i<nums.length;i++){
        memo[i] = Math.max(nums[i] + memo[i-1],nums[i]);
    }

    let max = nums[0];

    for(let i=1;i<memo.length;i++){
        max = Math.max(max,memo[i]);
    }

    return max;
};

LeetCode第54题:54. 螺旋矩阵

在这里插入图片描述
思路:

1.如果数组为空,返回空数组
2.定义4个边界以及当前方向
3.当左边界小于等于右边界,且上边界小于等于下边界时,执行while循环按照右,下,左,上的顺序,依次将路径上的字符添加到结果里
4.while循环结束后,返回结果

代码:

var spiralOrder = function(matrix) {
    if(matrix.length === 0){
        return [];
    }

    let top = 0;
    let bottom = matrix.length - 1;
    let left = 0;
    let right = matrix[0].length - 1;

    let direction = 'right';
    let result = [];
    /* 
    [1 , 2 , 3 , 4],
    [5 , 6 , 7 , 8],
    [9 , 10, 11 ,12]
    */
    while(left <= right && top <= bottom){
        if(direction === 'right'){
            for(let i=left;i<=right;i++){
                result.push(matrix[top][i]);
            }
            top++;
            direction = 'down';
        }else if(direction === 'down'){
            for(let i=top;i<=bottom;i++){
                result.push(matrix[i][right]);
            }
            right--;
            direction = 'left';
        }else if(direction === 'left'){
            for(let i=right;i>=left;i--){
                result.push(matrix[bottom][i]);
            }
            bottom--;
            direction = 'top';
        }else if(direction === 'top'){
            for(let i=bottom;i>=top;i--){
                result.push(matrix[i][left]);
            }
            left++;
            direction = 'right';
        }
    }
    return result;
};

LeetCode第55题:55. 跳跃游戏

在这里插入图片描述
解法1:递归版(动态规划)

var canJump = function(nums) {
    const totalLength = nums.length;
    const memo = Array(totalLength).fill(0);
    //dp
    memo[totalLength - 1] = 1;

    function jump(position){
        if(memo[position] === 1){
            return true;
        }else if(memo[position] === -1){
            return false;
        }

        const maxJump = Math.min(position + nums[position],totalLength - 1)
        for(let i=position+1;i<=maxJump;i++){
            const jumpReault = jump(i);
            if(jumpReault === true){
                memo[position] = 1;
                return true;
            }
        }
        memo[position] = -1;
        return false;
    }

    let result = jump(0);
    return result;
};

解法2:优化版1(bottom-up)

//bottom-up思路:
//从后往前判断,只要倒数第二个能到达最后一个,
//就判断从前面哪个能到倒数第二个,再继续依次向前推,直到数组最开始
var canJump = function(nums) {
    const totalLength = nums.length;
    const memo = Array(totalLength).fill(0);
    //dp
    memo[totalLength - 1] = 1;

    for(let i=totalLength - 2;i>=0;i--){
        const maxJump = Math.min(totalLength-1,i+nums[i]);
        for(let j=i+1;j<=maxJump;j++){
            if(memo[j] === 1){
                memo[i] = 1;
                break;
            }
        }
    }

    if(memo[0] === 1){
        return true;
    }else{
        return false;
    }
};

解法3:优化版2(贪心算法)

//贪心算法思路:
//依旧从后往前判断,刚开始的maxJump=nums.length - 1,
//判断索引+该索引对应的值是否大于maxJump,
//大于则maxJump就为该索引i,
//循环结束如果maxJump为0,则说明了到达了第一个数,证明成功了
var canJump = function(nums) {
    let maxJump = nums.length - 1;
    for(let i=nums.length-2;i>=0;i--){
        if(i+nums[i] >= maxJump){
            maxJump = i;
        }
    }
    return maxJump === 0;
};

LeetCode第56题:56. 合并区间

在这里插入图片描述
思路:

1.将数组中的区间按照起始位置排序
2.用curr数据记录当前合并的最大区间,遍历数组中的每一个区间,如果当前区间的起始位置小于curr的终点位置,则可以继续合并,所以合并并更新curr的起始和终止位置。如果当前区间的起始位置大于curr的终止位置,则无法合并所以将curr加入到result里,并用当前的区间替换curr的值

代码:

var merge = function(intervals) {
    if(intervals.length < 2){
        return intervals;
    }
    intervals.sort((a,b)=>{
      return a[0] - b[0];
    })
    let curr = intervals[0];
    let result = [];

    for(let interval of intervals){
        if(curr[1] >= interval[0]){
            curr[1] = Math.max(curr[1],interval[1]);
        }else{
            result.push(curr);
            curr = interval;
        }
    }

    if(curr.length !== 0){
        result.push(curr);
    }

    return result;
};

LeetCode第62题:62. 不同路径

在这里插入图片描述
代码:

//动态规划
  //到达每个格子的路劲总数等于到达该格子上面和左面的路径之和
  //依次累加
var uniquePaths = function(m, n) {
    const memo = [];
    //建立一个二维数组
    for(let i=0;i<n;i++){
        memo.push([]);
    }
    for(let row=0;row<n;row++){
        memo[row][0] = 1;
    }
    for(let col=0;col<m;col++){
        memp[0][col] = 1;
    }

    for(let row=1;row<n;row++){
        for(let col=1;col<m;col++){
            memo[row][col] = memo[row-1][col] + memo[row][col-1];
        }
    }

    return memo[n-1][m-1];
};

LeetCode第66题:66. 加一

在这里插入图片描述
代码:

var plusOne = function(digits) {
    for(let i=digits.length-1;i>=0;i--){
        if(digits[i] !== 9){
            digits[i]++;
            return digits
        }else{
            digits[i] = 0;
        }
    }

    const result = [1,...digits];
    return result;
};

LeetCode第70题:70. 爬楼梯

在这里插入图片描述
代码:

var climbStairs = function(n) {
    //memo[i-2] = 2
    //memo[i-1] = 3
    //memo[i] = memo[i-1] + memo[i-2] = 5

    const memo = [];
    memo[1] = 1;
    memo[2] = 2;
    //memo[3] = 3;
    //memo[4] = 5;

    for(let i=3;i<=n;i++){
        memo[i] = memo[i-2] + memo[i-1];
    }

    return memo[n];
};

LeetCode第73题:73. 矩阵置零

在这里插入图片描述
思路:

1.检查并标记第一行和第一列是否有0(firstColHasZero和firstRowHashZero)
2.使用第一行和第一列,来标记其余行列是否含有0
3.接下来,利用第一行和第一类的标0情况,将matrix中的数字标0
4.最后,处理第一行和第一列
  如果firstColHasZero等于true,将第一列全设为0
  如果firstRowHashZero等于true,将第一行全设为0

代码:

var setZeroes = function(matrix) {
    let firstColHashZero = false;
    let firstRowHashZero = false;

    //判断第一列是否有0
    for(let i=0;i<matrix.length;i++){
        if(matrix[i][0] === 0){
            firstColHashZero = true;
        }
    }

    //判断第一行是否有0
    for(let i=0;i<matrix.length;i++){
        if(matrix[0][i] === 0){
            firstRowHashZero = true;
        }
    }

    //排除第一行和第一列,标记其余行列是否含有0,
    //有0则将该0所对应的行、列所在的第一行、第一列数字标0
    for(let row=1;row<matrix.length;row++){
        for(let col=1;col<matrix[0].length;col++){
            if(matrix[row][col] === 0){
                matrix[row][0] = 0;
                matrix[0][col] = 0;
            }
        }
    }

    //利用第一行和第一类的标0情况,将matrix中的数字标0
    for(let row=1;row<matrix.length;row++){
        for(let col=1;col<matrix[0].length;col++){
            if(matrix[row][0] === 0 || matrix[0][col] === 0){
                matrix[row][col] = 0;
            }
        }
    }

    // 如果firstColHasZero等于true,将第一列全设为0
    if(firstColHashZero){
        for(let i=0;i<matrix.length;i++){
            matrix[i][0] = 0;
        }
    }

    //如果firstRowHashZero等于true,将第一行全设为0
    if(firstRowHashZero){
        for(let i=0;i<matrix[o].length;i++){
            matrix[0][i] = 0;
        }
    }

    return matrix;
};

LeetCode第83题:83. 删除排序链表中的重复元素

在这里插入图片描述
思路:

1.建立一个指针遍历整个链表
2.如果前一个和后一个相等,则删除下一个指针,否则指针后移

代码:

var deleteDuplicates = function(head) {
    let current = head;
    while(current !== null && current.next !==null){
        if(current.val === current.next.val){
            current.next = current.next.next;
        }else{
            current = current.next;
        }
    }

    return head;
};

LeetCode第206题:206. 反转链表

在这里插入图片描述
解法1:普通版

var reverseList = function(head) {
    let prev = null;
    let curr = head;
    let next = head;

    while(curr !== null){
        next = curr.next;
        curr.next = prev;
        prev = curr;
        curr = next;
    }
    
    return prev;
};

解法2:优化版

var reverseList = function(head) {
    let prev = null;
    let curr = head;

    while(curr !== null){
        [curr.next,prev,curr] = [prev,curr,curr.next];
    }
    
    return prev;
};

LeetCode第92题:92. 反转链表 II

在这里插入图片描述
解法1:普通版

//思路:
    //1、反转m至n之间的链表
    //2、将反转后的链表与原链表拼接
var reverseBetween = function(head, left, right) {
    let prev = null;
    let curr = head;
    let next = head;

    for(let i=1;i<left;i++){
        prev = curr;
        curr = curr.next;
    }

    let prev2 = prev;
    let curr2 = curr;

    for(let i=left;i<=right;i++){
        next = curr.next;
        curr.next = prev;
        prev = curr;
        curr = next;
    }

    if(prev2 !== null){
        prev2.next = prev;
    }else{
        head = prev;
    }

    curr2.next = curr;
    return head;
};

解法2:简化版

//思路:
    //1、反转m至n之间的链表
    //2、将反转后的链表与原链表拼接
var reverseBetween = function(head, left, right) {
    let prev = null;
    let curr = head;

    for(let i=1;i<left;i++){
        prev = curr;
        curr = curr.next;
    }

    let prev2 = prev;
    let curr2 = curr;

    for(let i=left;i<=right;i++){
         [curr.next,prev,curr] = [prev,curr,curr.next]
    }

    if(prev2 !== null){
        prev2.next = prev;
    }else{
        head = prev;
    }

    curr2.next = curr;
    return head;
};

LeetCode第121题:121. 买卖股票的最佳时机

在这里插入图片描述
思路:

1.设定两个变量,
   一个用来存储目前所在点左半边的最小点,
   另一个用来存储目前利润的最大值
2.遍历数组
   首先判断minPrice是否是最小值
   再判断maxProfit是否是最大值

代码:

var maxProfit = function(prices) {
    if(prices.length === 0){
        return 0;
    }

    let minPrice = prices[0];
    let maxProfit = 0;

    for(let i=0;i<prices.length;i++){
        if(prices[i] < minPrice){
            minPrice = prices[i];
        }else if(prices[i] - minPrice > maxProfit){
            maxProfit = prices[i] - minPrice;
        }
    }

    return maxProfit;
};

LeetCode第122题:122. 买卖股票的最佳时机 II

在这里插入图片描述
思路:

思路1:
    1.向上的曲线,底端买入,顶端卖出
    2.向下的曲线不买也不卖
思路2:
    将每一项和它的后一项进行对比,如果小于后一项,
    就把之差加到利润中

代码:

var maxProfit = function(prices) {
    if(prices.length === 0){
        return 0;
    }

    //思路1!!!
    /* let profit = 0, valley = prices[0], peak = prices[0];
    let i = 0;
    while(i<prices.length - 1){
        while(i<prices.length - 1 && prices[i] >= prices[1+1]){
            i++;
        }
        valley = prices[i];
        while(i<prices.length - 1 && prices[i] <= prices[i+1]){
            i++;
        }
        peak = prices[i];
        profit += peak - valley;
    } */

    //思路2!!!
    let profit = 0; 
    for(let i=0;i<prices.length - 1;i++){
        if(prices[i] < prices[i+1]){
            profit += prices[i+1] - prices[i];
        }
    }
    return profit;
};

LeetCode第123题:123. 买卖股票的最佳时机 III

在这里插入图片描述
代码:

var maxProfit = function(prices) {
    if(prices.length === 0){
        return 0;
    }
    //二维数组,行,列
    const dp = Array.from(Array(3),()=>new Array(prices.length));
    //将第一行,第一列都设为0
    for(let i=0;i<prices.length;i++){
        dp[0][i] = 0;
    }
    for(let i=0;i<3;i++){
        dp[i][0] = 0;
    }
    for(let i=1;i<3;i++){
        let maxProfit = -prices[0];
        for(let j=1;j<prices.length;j++){
            dp[i][j] = Math.max(dp[i][j-1],prices[j]+maxProfit);
            maxProfit = Math.max(maxProfit,dp[i-1][j] - prices[j]);
        }
    }

    return dp[2][prices.length-1];

};

LeetCode第125题:125. 验证回文串

在这里插入图片描述
思路:

1.用正则表达式去掉非数字和字母
2.如果字符串长度小于2,返回true
3.定义两个指针,一个在字符串开头,一个在字符串结尾
4.建议一个while循环,当left<right时执行循环,如果在任意地点s[left] !== s[right],return false,否则left++,right--,继续执行循环
5.当循环完成后都没有return false,则return true

代码:

var isPalindrome = function(s) {
    s = s.toLowerCase().replace(/[\W_]/g,"");

    if(s.length < 2){
        return true;
    }

    let left = 0;
    let right = s.length - 1;

    while(left < right){
        if(s[left] !== s[right]){
            return false;
        }
        left++;
        right--;
    }

    return true;
};

LeetCode第134题:134. 加油站

在这里插入图片描述
思路:

1.首先将所有加油站的油加起来,再把需要消耗的油全部加起来,如果前者 小于后者,则能走完一圈,继续算法,否则直接返回-1
2.从某个点开始逐步判断,如果走不通则从走不通的那个点重新开始判断

代码:

var canCompleteCircuit = function(gas, cost) {
    let totalGas = 0;
    let totalCost = 0;

    for(let i=0;i<gas.length;i++){
        totalCost += cost[i];
        totalGas += gas[i];
    }

    if(totalCost > totalGas){
        return -1; 
    }

    let currentGas = 0;
    let start = 0;
    for(let i=0;i<gas.length;i++){
        currentGas = currentGas - cost[i] + gas[i];
        if(currentGas < 0){
            currentGas = 0;
            start = i + 1;
        }
    }

    return start;
};

LeetCode第135题:135. 分发糖果

在这里插入图片描述

// 贪心算法
var candy = function(ratings) {
    const n = ratings.length;
    const left = new Array(n).fill(0);
    //从左向右遍历,找出右边比左边大的
    for(let i=0; i<n; i++) {
        if (i > 0 && ratings[i] > ratings[i-1]) {
            left[i] = left[i-1] + 1;
        } else {
            left[i] = 1;
        }
    }
    //从右向左遍历,找出左边比右边大的
    let right = 0, res = 0;
    for(let i=n-1; i>-1;i--) {
        if (i < n-1 && ratings[i] > ratings[i+1]) {
            right++;
        } else {
            right = 1;
        }
        res += Math.max(left[i], right);
    }

    return res;
};

LeetCode第141题:141. 环形链表

在这里插入图片描述
思路:

 1.设定两个指针,快指针每次走两步,慢指针每次走一步
 2.如果存在环,快指针和慢指针总会重合
 3.慢指针比快指针快几步,快指针就能几步追上慢指针

代码:

var hasCycle = function(head) {  
    if(head === null){
        return false;
    }

    let slow = head;
    let fast = head;
    while(fast.next !== null && fast.next.next !== null){
        slow = slow.next;
        fast = fast.next.next;
        if(slow === fast){
            return true;
        }
    }

    return false;
};

LeetCode第142题:142. 环形链表 II

在这里插入图片描述
代码:

var detectCycle = function(head) {    
    if(head === null){
        return null;
    }

    let slow = head;
    let fast = head;
    let isCycle = false;
    while(fast.next !== null && fast.next.next !== null){
        slow = slow.next;
        fast = fast.next.next;
        if(slow === fast){
            isCycle = true;
            break;
        }
    }

    if(!isCycle){
        return null;
    }

    fast = head;
    while(slow !== fast){
        slow = slow.next;
        fast = fast.next;
    }

    return fast;
};

LeetCode第152题:152. 乘积最大子数组

在这里插入图片描述
代码:

var maxProduct = function(nums) {
    const maxProductMemo = [];
    const minProductMemo = [];
    maxProductMemo[0] = nums[0];
    minProductMemo[0] = nums[0];

    let max = nums[0];

    for(let i=1;i<nums.length;i++){
        //乘minProductMemo的原因在于nums[i]可能是个负值,
        //minProductMemo也可能是负值,负负得正
        maxProductMemo[i] = Math.max(nums[i],nums[i]*maxProductMemo[i-1],nums[i]*minProductMemo[i-1]);
        minProductMemo[i] = Math.min(nums[i],nums[i]*maxProductMemo[i-1],nums[i]*minProductMemo[i-1]);
        max = Math.max(max,maxProductMemo[i]);
    }

    return max;
};

LeetCode第153题:153. 寻找旋转排序数组中的最小值

在这里插入图片描述
思路:

1.如果数组长度为1,返回唯一的一个数
2.定义两个指针,第一个left指向数组开头,第二个right指向数组结尾
3.检查数组是否被翻转,如果没有,则返回数组里的第一个数
4.当left小于right时,取中间作为mid进行二分搜索,如果mid的左边一个数大于mid,或者mid右边的一个数小于mid,则返回mid
5.否则的话,如果left所在的数小于mid,则将left右移至mid+1位置(砍掉左半边)
6.否则的话,将right左移至mid-1的位置(砍掉右半边)

代码:

var findMin = function(nums) {
    if(nums.length === 1){
        return nums[0];
    }

    let left = 0, right = nums.length - 1;

    if(nums[right] > nums[0]){
        return nums[0];
    }

    while(left < right){
        let mid = Math.floor(left + (right - left) / 2);
        if(nums[mid] > nums[mid + 1]){
            return nums[mid + 1];
        }
        if(nums[mid - 1] > nums[mid]){
            return nums[mid];
        }
        if(nums[mid] > nums[left]){
            left = mid + 1;
        }else{
            right = mid - 1;
        }
    }
};

LeetCode第160题:160. 相交链表

在这里插入图片描述
代码:

var getIntersectionNode = function(headA, headB) {
    let n1 = headA;
    let n2 = headB;

    while(n1 !== n2){
        if(n1 === null){
            n1 = headB;
        }else{
            n1 = n1.next;
        }

        if(n2 === null){
            n2 = headA;
        }else{
            n2 = n2.next;
        }
    }

    return n1;
};

LeetCode第187题:187. 重复的DNA序列

在这里插入图片描述
解法1:

var findRepeatedDnaSequences = function(s) {
    const map = new Map();
    const result = [];
    let i = 0;
    while(i + 10 <= s.length){
        const dna = s.substring(i,i+10);
        if(map.get(dna) === undefined){
            map.set(dna,1);
        }else if(map.get(dna) === 1){
            map.set(dna,2);
            result.push(dna);
        }else{
            map.get(dna,map.get(dna) + 1);
        }
        i++;
    }
    return result;
};

解法2:

var findRepeatedDnaSequences = function(s) {
    const set = new Set(),result = new Set();
    let i = 0;
    while(i + 10 <= s.length){
        const dna = s.substring(i,i+10);
        if(set.has(dna)){
           result.add(dna);
        }else{
            set.add(dna);
        }
        i++;
    }
    return Array.from(result);
};

LeetCode第198题:198. 打家劫舍

在这里插入图片描述
解法1:

var rob = function(nums) {
    if(nums.length === 0){
        return 0;
    }
    if(nums.length === 1){
        return nums[0];
    }

    const memo = [];
    memo[0] = nums[0];
    memo[1] = Math.max(nums[0],nums[1]);
    for(let i=2;i<nums.length;i++){
        memo[i] = Math.max(nums[i] + memo[i-2],memo[i-1]);
    }

    return memo[nums.length - 1];
};

解法2:

var rob = function(nums) {
    if(nums.length === 0){
        return 0;
    }
    if(nums.length === 1){
        return nums[0];
    }

    let prev2 = nums[0];
    let prev1 = Math.max(nums[0],nums[1]);
    for(let i=2;i<nums.length;i++){
        const temp = Math.max(nums[i] + prev2,prev1);
        prev2 = prev1;
        prev1 = temp;
    }

    return prev1;
};

LeetCode第200题:200. 岛屿数量

在这里插入图片描述

代码:

//bfs -- 广度优先搜索(上下左右一次处理完,往外扩散再上下左右)
//dfs -- 深度优先搜索(上下左右,先把一条路走完,再返回去处理)
var numIslands = function(grid) {
    let count = 0;

    function dfs(row,col){
        if(row<0 || row>=grid.length || col<0 || col>=grid[0].length || grid[row][col] === '0'){
            return;
        }
        grid[row][col] = '0';
        dfs(row-1 , col);
        dfs(row+1 , col);
        dfs(row, col-1);
        dfs(row, col+1);
    }

    for(let row=0;row<grid.length;row++){
        for(let col=0;col<grid[0].length;col++){
            if(grid[row][col] === '1'){
                count++;
                dfs(row,col);
            }
        }
    }

    return count;
};

LeetCode第215题:215. 数组中的第K个最大元素

在这里插入图片描述

// 堆排序

LeetCode第217题:217. 存在重复元素

在这里插入图片描述

代码:

var containsDuplicate = function(nums) {
    const set = new Set();
    for(let i=0;i<nums.length;i++){
        if(set.has(nums[i])){
            return true;
        }
        set.add(nums[i]);
    }
    return false;
};

LeetCode第219题:219. 存在重复元素 II

在这里插入图片描述
代码:

var containsNearbyDuplicate = function(nums, k) {
    const map = new Map();

    for(let i=0;i<nums.length;i++){
        if(map.has(nums[i]) && (i - map.get(nums[i]) <= k)){
            return true;
        }else{
            map.set(nums[i],i);
        }
    }

    return false;
};

LeetCode第238题:238. 除自身以外数组的乘积

在这里插入图片描述
代码:

var productExceptSelf = function(nums) {
    const result = Array(nums.length).fill(1);

    let product = 1;
    for(let i=0;i<nums.length;i++){
        result[i] = result[i] * product;
        product = product * nums[i];
    }

    product = 1;
    for(let i=nums.length - 1;i>=0;i--){
        result[i] = result[i] * product;
        product = product * nums[i];
    }

    return result;  
};

LeetCode第242题:242. 有效的字母异位词

在这里插入图片描述
思路:

1.如果两个数组长度不一致,则返回false
2.创建一个map,用来存储每个字符出现的次数
3.对于第一个单词的每个字母,也就是s1[i],在map里将出现次数+1
  对于第二个单词的每个字母,也就是s2[i],在map里将出现次数-1
4.遍历完成后,检查map里的每一个字母出现的次数是不是0,如果有一个非0的字母,返回false,否则返回true

代码:

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

    const map = new Map();
    
    for(let i=0;i<s.length;i++){
        if(map.has(s[i])){
            map.set(s[i],map.get(s[i])+1);
        }else{
            map.set(s[i],1);
        }

        if(map.has(t[i])){
            map.set(t[i],map.get(t[i])-1);
        }else{
            map.set(t[i],-1);
        }
        
    }

    for(const letter of map){
        if(letter[1] !== 0){
            return false;
        }
    }

    return true;
};

LeetCode第283题:283. 移动零

在这里插入图片描述
思路:

将非0的数字移到数字开头,然后将剩余的位置补上0,用i和j控制

代码:

var moveZeroes = function(nums) {
    let j = 0;

    for(let i=0;i<nums.length;i++){
        if(nums[i] !== 0){
            nums[j] = nums[i];
            j++;
        }
    }

    for(i=j;i<nums.length;i++){
        nums[i] = 0;
    }

    return nums;
};

LeetCode第328题:328. 奇偶链表

在这里插入图片描述
代码:

var oddEvenList = function(head) {
    if(head === null){
        return null;
    }

    if(head.next === null){
        return head;
    }

    let odd = head;
    let even = head.next;
    let evenHead = head.next;
    while(even !== null && even.next !== null){
        odd.next = odd.next.next;
        odd = odd.next;
        even.next = even.next.next;
        even = even.next;
    }

    odd.next = evenHead;

    return head;
};

LeetCode第349题:349. 两个数组的交集

在这里插入图片描述
代码:

//交集即nums1中有,nums2中也有的元素
var intersection = function(nums1, nums2) {
    const result = new Set();
    const set = new Set(nums2);

    /* for(num of nums2){
        set.add(num);
    } */

    for(num of nums1){
        //数组搜索值,复杂度O(n)
        //Set Map --- .has  复杂度O(1)
        if(set.has(num)){
            result.add(num);
        }
    }

    return Array.from(result);
};

LeetCode第419题:419. 甲板上的战舰

在这里插入图片描述
解法1:把相邻的X全都转化成 .

var countBattleships = function(board) {
    let result = 0;
    for(let row=0;row<board.length;row++){
        for(let col=0;col<board[0].length;col++){
            if(board[row][col] === 'X'){
                result++;
                dfs(row,col);
            }
        }
    }

    function dfs(row,col){
        if(row<0 || row>=board.length || col<0 || col>=board[0].length || board[row][col] !== 'X'){
            return;
        }
        board[row][col] = '.';
        dfs(row-1,col);
        dfs(row+1,col);
        dfs(row,col+1);
        dfs(row,col-1);
    }

    return result;
};

解法2:不管相邻的X,继续往下进行

var countBattleships = function(board) {
    let result = 0;
    for(let row=0;row<board.length;row++){
        for(let col=0;col<board[0].length;col++){
            if(board[row][col] === 'X'){
                //左面
                if(row>0 && board[row-1][col] === 'X'){
                    continue;
                }
                //上面
                if(col>0 && board[row][col-1] === 'X'){
                    continue;
                }
                result++;
            }
        }
    }

   return result;
};

LeetCode第445题:445. 两数相加 II

在这里插入图片描述
思路:

1.将这两个链表里的数都放到栈里,然后依次相加,注意存储进位
2.将第一个和作为链表的最后一项,把它的下一项设为null,即curr的初始值
3.然后把node赋值给curr,依次循环
4.检查最后的进位如果为1,继续上述操作,将1设为链表第一项

代码:

var addTwoNumbers = function(l1, l2) {
    const stack1 = [], stack2 = [];
    while(l1 !== null){
        stack1.push(l1.val);
        l1 = l1.next;
    }
    while(l2 !== null){
        stack2.push(l2.val);
        l2 = l2.next;
    }

    let carry = 0, curr = null;

    while(stack1.length!==0 || stack2.length!==0){
        let sum = 0;
        if(stack1.length !== 0){
            sum += stack1.pop();
            // const sum = stack1.pop();
            // sum = sum + num;
        }
        if(stack2.length !== 0){
            sum += stack2.pop();
            // const num = stack1.pop();
            // sum = sum + num;
        }

        sum += carry;

        const node = new ListNode(sum % 10);
        carry = Math.floor(sum / 10);
        
        node.next = curr;
        curr = node;
    }

    if(carry !== 0){
        const node = new ListNode(carry);
        node.next = curr;
        curr = node;
    }

    return curr;
};

LeetCode第509题:509. 斐波那契数

在这里插入图片描述
解法1:top-down

var fib = function(n) {
    if(n <= 1){
        return n;
    }

    const cache = [];
    cache[0] = 0;
    cache[1] = 1;

    function memoize(number){
        if(cache[number] !== undefined){
            return cache[number];
        }

        cache[number] = memoize(number-1) + memoize(number-2);
        return cache[number];
    }

    const result = memoize(n);

    return result;
};

解法2:bottom-up

var fib = function(n) {
    if(n <= 1){
        return n;
    }

    const cache = [];
    cache[0] = 0;
    cache[1] = 1;
    for(let i=2;i<=n;i++){
        cache[i] = cache[i-1] + cache[i-2];
    }

    return cache[n];
};

解法3:bottom-up(空间复杂度优化)

var fib = function(n) {
    if(n <= 1){
        return n;
    }

    let prev2 = 0;
    let prev1 = 1;
    let result = 0;
    for(let i=2;i<=n;i++){
        result = prev1 + prev2;
        prev2 = prev1;
        prev1 = result;
    }

    return result;
};

LeetCode第680题:680. 验证回文字符串 Ⅱ

在这里插入图片描述
代码:

var validPalindrome = function(s) {
    function isPalindrome(left,right){
        while(left < right){
            if(s[left] !== s[right]){
                return false;
            }
            left++;
            right--;
        }
        return true;
    }

    let left = 0;
    let right = s.length - 1;
    while(left < right){
        if(s[left] !== s[right]){
            const result = isPalindrome(left+1,right) || isPalindrome(left,right-1);
            return result;
        }
        left++;
        right--;
    }

    return true;
};

LeetCode第695题:695. 岛屿的最大面积

在这里插入图片描述
代码:

var maxAreaOfIsland = function(grid) {
    let result = 0;
    for(let row=0;row<grid.length;row++){
        for(let col=0;col<grid[0].length;col++){
            if(grid[row][col] === 1){
                const count = dfs(row,col);
                result = Math.max(count,result);
            }
        }
    }

    function dfs(row,col){
        if(row<0 || row>=grid.length || col<0 || col>=grid[0].length || grid[row][col] === 0){
            return 0;
        }

        grid[row][col] = 0;

        let count = 1;

        count += dfs(row-1,col);
        count += dfs(row+1,col);
        count += dfs(row,col-1);
        count += dfs(row,col+1);

        return count;
    }

    return result;
};

LeetCode第704题:704. 二分查找

在这里插入图片描述
思路:

1.left=0,right=length-1,mid=left+(right-left)/2
2.当left<=right,
  如果mid上的值等于target,返回mid,如果小于target,left=mid+1(砍掉左半边),
  如果大于target,right=mid-1(砍掉右半边)
3.如果while循环结束后都没有找到target,返回-1

代码:

var search = function(nums, target) {
    let left = 0, right = nums.length - 1;
    while(left <= right){
        mid = Math.floor(left + (right - left) / 2);
        if(nums[mid] === target){
            return mid;
        }else if(nums[mid] < target){
            left = mid + 1;
        }else{
            right = mid - 1;
        }
    }
    return -1;
};

LeetCode第733题:733. 图像渲染

在这里插入图片描述
代码:

var floodFill = function(image, sr, sc, newColor) {
    if(image[sr][sc] === newColor){
        return image;
    }

    const oldColor = image[sr][sc];

    function dfs(sr,sc){
        if(sr<0 || sr>=image.length || sc<0 || sc>=image[0].length || image[sr][sc] !== oldColor){
            return;
        }
        image[sr][sc] = newColor;
        dfs(sr-1,sc);
        dfs(sr+1,sc);
        dfs(sr,sc-1);
        dfs(sr,sc+1);
    }

    dfs(sr,sc);

    return image;
};

LeetCode第796题:796. 旋转字符串

在这里插入图片描述代码:

//在s和goal的长度相等的情况下,在s后面再连接上一个s,则所有可能的情况都包含在这个新的字符串中,只需查看这个新字符串中是否包含目标字符串
var rotateString = function(s, goal) {
    if(s.length !== goal.length){
        return false;
    }

    const str = s + s;

    return str.includes(goal);
};

LeetCode第836题:836. 矩形重叠

在这里插入图片描述
思路:

 rec1右 <= rec2左
 rec1左 >= rec2右
 rec1下 >= rec2上
 rec1上 <= rec2下

代码:

var isRectangleOverlap = function(rec1, rec2) {
    if(rec1[2]<=rec2[0] || rec1[0]>=rec2[2] || rec1[1]>=rec2[3] || rec1[3]<=rec2[1]){
        return false;
    }else{
        return true;
    }
};

LeetCode第844题:844. 比较含退格的字符串

在这里插入图片描述
代码:

var backspaceCompare = function(s, t) {
    let i = s.length - 1, j = t.length - 1;
    let backspaceS = 0, backspaceT = 0;

    while(i>=0 || j>=0){
        while(i>=0){
            if(s[i] === '#'){
                backspaceS++;
                i--;
            }else if(backspaceS > 0){
                backspaceS--;
                i--;
            }else{
                break;
            }
        }

        while(j>=0){
            if(t[j] === '#'){
                backspaceT++;
                j--;
            }else if(backspaceT > 0){
                backspaceT--;
                j--;
            }else{
                break;
            }
        }

        if(s[i] !== t[j]){
            return false;
        }

        if((i<0 && j>=0) || (i>=0 && j<0)){
            return false;
        }
        i--;
        j--;
    }

    return true;

};

LeetCode第876题:876. 链表的中间结点

在这里插入图片描述
代码:

var middleNode = function(head) {
    let slow = head;
    let fast = head;
    while(fast !== null && fast.next !== null){
        slow = slow.next;
        fast = fast.next.next;
    }

    return slow;
};

LeetCode第904题:904. 水果成篮

在这里插入图片描述
代码:

var totalFruit = function(fruits) {
    const map = new Map();
    let max = 1;
    let j = 0;
    for(let i=0;i<fruits.length;i++){
        map.set(fruits[i],i);
        if(map.size > 2){
            let minIndex = fruits.length - 1;
            for(const [fruit,index] of map){
                if(index < minIndex){
                    minIndex = index;
                }
            }
            map.delete(fruits[minIndex]);
            j = minIndex + 1;
        }
        max = Math.max(max,i-j+1);
    }
    return max;
};

LeetCode第905题:905. 按奇偶排序数组

在这里插入图片描述
代码:

var sortArrayByParity = function(nums) {
    let i = 0, j = nums.length - 1;
    while(i < j){
        if(nums[i]%2 === 1 && nums[j]%2 === 0){
            [nums[i],nums[j]] = [nums[j],nums[i]];
            i++;
            j--;
        }
        // }else if(nums[i]%2 === 0 && nums[j]%2 === 0){
        //     i++;
        // }else if(nums[i]%2 === 0 && nums[j]%2 === 1){
        //     i++;
        //     j--;
        // }else{
        //     j--;
        // }
        if(nums[i]%2 === 0){
            i++;
        }
        if(nums[j]%2 === 1){
            j--;
        }
    }
    return nums;
};

LeetCode第922题:922. 按奇偶排序数组 II

在这里插入图片描述

代码:

var sortArrayByParityII = function(nums) {
    let j = 1;
    for(let i=0;i<nums.length;i+=2){
        if(nums[i]%2 === 1){
            while(nums[j]%2 === 1 && j<nums.length){
                j+=2;
            }
            [nums[i],nums[j]] = [nums[j],nums[i]];
        }
    }
    return nums;
};
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值