【算法】九月算法打卡

2022-09-01

外观数列

在这里插入图片描述

后一项是前一项的描述

获取第 n项数列,需要获取第n-1项数列。由此得出要采用递归回溯的形式

/**
 * @param {number} n
 * @return {string}
 */
var countAndSay = function(n) {
    if(n == 1) return "1";
    // 上一串字符串
    let prevSeq = countAndSay(n - 1);
    
    // 返回结果
    let res = "";

    // 上一个数字
    let lastNum = prevSeq.charAt(0);
    // 出现的次数
    let numCount = 0;

    for (let i = 0; i < prevSeq.length; i++) {
        if (prevSeq.charAt(i) == lastNum) {
            ++numCount;
        } else {
            res += numCount;
            res += lastNum;

            // 更新上一个数字
            lastNum = prevSeq.charAt(i);
            numCount = 1;
        }

        // 特殊情况
        if (i == prevSeq.length - 1) {
            res += numCount;
            res += lastNum;
        }
    }
    return res;
};

组合总合

在这里插入图片描述

关键点:无重复同一个数字可以无限制重复被选取

采用递归回溯的形式

1、将数组进行升序排序

2、遍历数组进行递归

  • 关键:每次递归前需要判断当前数值是否小于目标值,小于则才可以添加进去
  • 关键:当前数值进行递归结束后,需要将当前数值进行回溯(即去除该值)

3、递归结束的标志:目标值为0

/**
 * @param {number[]} candidates
 * @param {number} target
 * @return {number[][]}
 */
var combinationSum = function(candidates, target) {
      // 升序
      candidates.sort((a, b) => a - b);
      // 结果
      let res = [];
     
     let dfs = function (start, target, comine) {
         // 满足条件
         if (target == 0) {
             res.push([...comine])
         }

         for(let i = start; i < candidates.length; i++) {
             // 当前值大于目标值,无需添加
             if (target < candidates[i]) return;
             // 该值可能满足条件
             comine.push(candidates[i]);
             dfs(i, target - candidates[i], comine);
             comine.pop(); // 回溯
         }
     }
     dfs(0, target, []);
     return res;
};

2022-09-02

组合总和II

在这里插入图片描述

关键点:每一个数字只能使用一次

实现逻辑跟上面的一致,只不过在递归前需要添加一个判断条件

当前位置的数值等于前一个数值时,并且当前数值位置要大于start,则该值不能添加进去

if (i > start && candidates[i] == candidates[i - 1]) continue
/**
 * @param {number[]} candidates
 * @param {number} target
 * @return {number[][]}
 */
var combinationSum2 = function(candidates, target) {
     candidates.sort((a, b) => a - b);
     let res = [];
     let dfs = function (start, target, combin) {
         // 剪枝
         if (target == 0) res.push([...combin]);

         for(let i = start; i < candidates.length; i++) {
             if (candidates[i] > target) break;
             // 打头元素不能相同,不然重复
             if (i > start && candidates[i] === candidates[i - 1])continue;

             combin.push(candidates[i]);
             dfs(i+1, target - candidates[i], combin);
             combin.pop();
         }
         
     }
     dfs(0, target, []);
     return res;
};
组合总和III

在这里插入图片描述

实现逻辑跟组合总和III一致

/**
 * @param {number} k
 * @param {number} n
 * @return {number[][]}
 */
var combinationSum3 = function(k, n) {
   let candidates = [1, 2, 3, 4, 5, 6, 7, 8, 9];
   let res = [];
   let dfs = function(start, target, combin) {
       if (combin.length == k && target == 0) {
           res.push([...combin]);
           return;
       }

       for(let i = start; i < candidates.length; i++) {
           if(candidates[i] > target) break;

           if (i > start && candidates[i] == candidates[i - 1]) continue;

           combin.push(candidates[i])
           dfs(i + 1, target - candidates[i], combin);
           combin.pop();
       }

   }
   dfs(0, n, []);
   return res;
};

2022-09-03

解数独

在这里插入图片描述

1、需要实现 isValid() 判断当前填入值后,当前数独是否有效。

2、从 1 到 9 不断去尝试填入的值是否有效

/**
 * @param {character[][]} board
 * @return {void} Do not return anything, modify board in-place instead.
 */
var solveSudoku = function (board) {
  function isValid(row, col, val, board) {
    // 行不能重复
    for (let i = 0; i < 9; i++) {
      if (board[row][i] === val) return false
      
    }
    // 列不能重复
    for (let i = 0; i < 9; i++) {
      if (board[i][col] === val) return false
    }
    let boxRow = Math.floor(row / 3) * 3
    let boxCol = Math.floor(col / 3) * 3

    for (let i = boxRow; i < boxRow + 3; i++) {
      for (let j = boxCol; j < boxCol + 3; j++) {
        if (board[i][j] === val) return false
        
      }
    }

    return true
  }

  let helper = function () {
    for (let i = 0; i < 9; i++) {
      for (let j = 0; j < 9; j++) {
        if (board[i][j] !== ".") continue;
        // 不断尝试  
        for (let val = 1; val <= 9; val++) {
          if (isValid(i, j, `${val}`, board)) {
            board[i][j] = `${val}`
            if (helper()) return true;
            // 当前位置 board[i][j] 不能填入数字 val  
            board[i][j] = "."
          }
        }
        return false;
      }
    }
    return true;
  }
  helper();
  return board;
};
接雨水

在这里插入图片描述

1、左右指针,左指针在最左边,右指针在最右边,两者不断向中间靠拢

2、移动前需要判断 当前左指针指向的位置height[l],与当前保存的左边界最大值lmax进行比较,并保存最大值

3、右指针同理

4、此时若 左边界(lmax)小于右边界(rmax),则左边界向中间移动。反之,右向中间移动

5、移动过程中计算当前位置接到的雨水

  • res += (lmax - height[l]) lmax < rmax
  • res += (rmax - height[r]) rmax <= lmax
/**
 * @param {number[]} height
 * @return {number}
 */
var trap = function(height) {
    let res = 0;
    let l = 0; 
    let r = height.length - 1;

    let lmax = 0; // 左边最大值
    let rmax = 0; // 右边最大值

    while(l < r) {
        // 更新最大值
        lmax = Math.max(lmax, height[l]);
        rmax = Math.max(rmax, height[r]);

        if (lmax < rmax) { // 左边短于右边
            res += (lmax - height[l])
            l++;
        } else { // 右边短于左边
           res += (rmax - height[r])
           r--;
        }
    } 
    return res;
};

2022-09-04

缺失的第一个正数

在这里插入图片描述

题意是根据所给数组中没有出现的最小正整数。

解法:

  • 创建 nums.length 个桶,每一个桶对应存发该位置应该存放的数字(i+1 == num
  • 最后遍历所有桶,那个桶为空,说明缺少的正整数为i + 1

交换的必须满足以下几个条件:

  • 交换值val 必须在val > 0 && val <= len;
/**
 * @param {number[]} nums
 * @return {number}
 */
var firstMissingPositive = function(nums) {
     let len = nums.length;
     let swap = function(nums, i, j) {
         let temp = nums[i];
         nums[i] = nums[j];
         nums[j] = temp;
     }

     // 将每一个值找到对应桶的位置
     for (let i= 0; i < len;) {
         let val = nums[i];
         if (val > 0 && val <= len && val != i + 1 && nums[val - 1] != val) {
             swap(nums, i, val - 1);
         } else {
             i++;
         }
     }

     // 找每一个桶是否位置对应
     for(let i = 0; i < len; i++) {
         if (nums[i] != i + 1) return i + 1;
     }
     return len + 1;
};
字符串相乘

在这里插入图片描述

字符串相乘

关键点:

  • 对应位置相乘的值对应放入的位置为(i + j),进位为(i + j + 1)
  • 计算结束后,需要判断结果数组第一位res[0]是否为0,为0需要删除
/**
 * @param {string} num1
 * @param {string} num2
 * @return {string}
 */
var multiply = function(num1, num2) {
     if (num1 == '0' || num2 == '0') return '0';

     let len1 = num1.length;
     let len2 = num2.length;

     // 结果数组
     let res = new Array(len1 + len2).fill(0);

     for (let i = len1 - 1; i >= 0; i--) {
         for (let j = len2 - 1; j >= 0; j--) {
             const mul = num1[i] * num2[j];
             // 乘积在结果数组的位置
             const p1 = j + i;
             // 进位位置
             const p2 = i + j + 1; 

             const sum = res[p2] + mul;
             res[p1] += Math.floor(sum / 10);
             res[p2] = sum % 10
         }
     }

     if (res[0] == 0) res.shift()
     return res.join("")
};

2022-09-05

跳跃游戏

在这里插入图片描述

/**
 * @param {number[]} nums
 * @return {boolean}
 */
var canJump = function(nums) {
    let len = nums.length;
    // 距离
    let distance = len - 1; 
    // 倒数第二个开始
    let last = len - 2;

    for (let i = last; i >= 0; i--) {
        // nums[i] + i 代表当前位置(i)能够到达最远右边的距离
        if (nums[i] + i >= distance) {
          // 进入到这里,说明当前 i 可以到达最右边
          
          // 接着distance更新为(最左边到达i的距离) 
          distance = i;

          // 判断i之前有哪些点可以到达 i,由此循环
        }
    }
    // 遍历完数组, distance 为 0 说明可以进行跳跃
    return distance === 0;
  }
跳跃游戏II

在这里插入图片描述

/**
 * @param {number[]} nums
 * @return {number}
 */
var jump = function(nums) {
    // 最远距离
    let maxPos = 0;
    // 最远点
    let end = 0;
    // 步长
    let ans = 0;
    for(let i = 0; i < nums.length - 1; i++) {
        maxPos = Math.max(maxPos, nums[i] + i);
        if (i == end) { // 到达最远边界
            end = maxPos;
            ans++;
        }
    }
    return ans;
};

2022-09-06

全排列

在这里插入图片描述

/**
 * @param {number[]} nums
 * @return {number[][]}
 */
var permute = function (nums) {
  let res = [];
  let dfs = function (nums, tmp, visited) {

    if (tmp.length == nums.length) {
      res.push([...tmp]);
      return;
    }

    for (let i = 0; i < nums.length; i++) {
      if (visited[i] == 1) continue;
      visited[i] = 1;

      tmp.push(nums[i]);

      dfs(nums, tmp, visited);

      visited[i] = 0;
      tmp.pop();
    }
  }
  dfs(nums, [], []);
  return res;
};
全排列II

在这里插入图片描述

var permuteUnique = function(nums) {
    const ans = [];
    const vis = new Array(nums.length).fill(false);
    const dfs = (size, tmp) => {
        if (size === nums.length) {
            ans.push([...tmp]);
            return;
        }

        for (let i = 0; i < nums.length; ++i) {
            if (vis[i] || (i > 0 && nums[i] == nums[i - 1] && !vis[i - 1])) {
                continue;
            }
            tmp.push(nums[i]);
            vis[i] = true;
            dfs(size + 1, tmp);
            vis[i] = false;
            tmp.pop();
        }
    }
    nums.sort((a, b) => a - b);
    dfs(0, []);
    return ans;
};

2022-09-07

旋转图像

在这里插入图片描述

在这里插入图片描述

/**
 * @param {number[][]} matrix
 * @return {void} Do not return anything, modify matrix in-place instead.
 */
var rotate = function(matrix) {

    // 对角翻转
    for (let i = 0; i < matrix.length; i++) {
        for (let j = 0; j < i; j++) {
            let temp = matrix[i][j];
            matrix[i][j] = matrix[j][i];
            matrix[j][i] = temp;
        }
    }
    // 左右交换
    for(let i = 0; i < matrix.length; i++) {
        for (let j = 0; j < Math.ceil(matrix.length / 2); j++) {
             let temp = matrix[i][j]; 
             matrix[i][j] = matrix[i][matrix.length - j - 1];
             matrix[i][matrix.length - j - 1] = temp;
        }
    }
    return matrix;
};
字母异位分组

在这里插入图片描述

/**
 * @param {string[]} strs
 * @return {string[][]}
 */
var groupAnagrams = function(strs) {
    let map = new Map();
    for (let i = 0; i < strs.length; i++) {

        // acb => abc 把 abc当作map的key值
        let key = strs[i].split('').sort().join('');

        if (!map.has(key)) map.set(key, [])

        map.get(key).push(strs[i]);
    }
    return [...map.values()];
};

2022-09-08

pow(x, n)

在这里插入图片描述

var myPow = function(x, n) {
    if(n ==0 || n ==1) {
        return n == 0 ? 1: x
    }else if(n < 0){
        return myPow(1/x, Math.abs(n))
    }else{
        return n % 2 == 0 ? myPow(x * x , n/2) :  myPow(x * x ,Math.floor(n/2))* x
    }
};
最大子数组和

在这里插入图片描述

/**
 * @param {number[]} nums
 * @return {number}
 */
var maxSubArray = function(nums) {
    let ans = nums[0];
    let sum = 0;
    for(const num of nums) {
        if(sum > 0) {
            sum += num;
        } else {
            sum = num;
        }
        ans = Math.max(ans, sum);
    }
    return ans;
};

2022-09-09

螺旋矩阵

在这里插入图片描述

在这里插入图片描述

/**
 * @param {number[][]} matrix
 * @return {number[]}
 */
var spiralOrder = function(matrix) {
    let res = [];
    let m = matrix.length;
    let n = matrix[0].length;

    // 上边界
    let up = 0;
    // 下边界
    let down = m -1;
    // 左边界
    let left = 0;
    // 右边界
    let right = n - 1;

    // 遍历
    while(true) {
        // 从左到右
        for (let i = left; i <= right; i++) res.push(matrix[up][i]);
        // 上边界下移
        if (++up > down) break;
         
        // 从上到下
        for (let i = up; i <= down; i++) res.push(matrix[i][right]);
        // 右边界左移
        if (--right < left) break;

        // 从右到左
        for (let i = right; i >= left; i--) res.push(matrix[down][i]);
        // 下边界上移
        if (--down < up) break;

        // 从下到上
        for (let i = down; i >= up; i--) res.push(matrix[i][left]);
        // 左指针右移
        if (++left > right) break;
    }
    return res;
};
螺旋矩阵II

在这里插入图片描述

/**
 * @param {number} n
 * @return {number[][]}
 */
var generateMatrix = function(n) {
    let res = Array(n).fill().map(() => Array(n));

    // 上边界
    let up = 0;
    // 下边界
    let down = n -1;
    // 左边界
    let left = 0;
    // 右边界
    let right = n - 1;

    let cur = 1; 
    // 遍历
    while(true) {
        // 从左到右
        for (let i = left; i <= right; i++) res[up][i] = cur++;
        // 上边界下移
        if (++up > down) break;
         
        // 从上到下
        for (let i = up; i <= down; i++) res[i][right] = cur++;
        // 右边界左移
        if (--right < left) break;

        // 从右到左
        for (let i = right; i >= left; i--) res[down][i] = cur++;
        // 下边界上移
        if (--down < up) break;

        // 从下到上
        for (let i = down; i >= up; i--) res[i][left] = cur++;
        // 左指针右移
        if (++left > right) break;
    }
    return res;
};

2022-09-10

N皇后

在这里插入图片描述

var solveNQueens = function(n) {
    // 当前填入的结果
    let tmp = new Array(n).fill(-1);

    // 最终返回的结果 res[i] = j 代表 在第 i 行 第 j 列放入皇后(行与列从0开始计算)
    let res = [];
    // 记录当前哪些位置不能放入皇后
    let cache = [];

    /**
     * 
     * @param {number} index 当前皇后在第几行 
     * @param {*} tmp 当前填入的结果
     * @param {*} cache 
     * @returns 
     */
    let dfs = function(index, tmp, cache) {
        // 最后一个皇后(结束)
        if (index == n) {
            res.push(tmp);
            return;
        }

        for (let i = 0; i < n; i++) {
           //该位置不能放皇后
            if (cache.indexOf(index + "," + i) > -1) continue;
            
            let arr = [...tmp];
            // 放入皇后(在 第 index 行 第 i 列)
            arr[index] = i;

            // 判断填入的皇后是否符合条件
            let f = 0;
            for (let p = 0; p < n; p++) {
                for (let q = 0; q < n; q++) {
                    
                    if (cache.indexOf(p + ',' + q) == -1) {
                        // 计算当 在 第 index 行 第 i 列放入皇后后,其他哪些位置不能放入皇后
                        if (index == p || i == q || p -index == q - i || p+ q == index + i) {
                            cache.push(p + ',' + q);
                            f++;
                        }
                    }
                }
            }
            dfs(index + 1, arr, cache);
            while(f--) cache.pop(); // 删除标记
        }
    }
    dfs(0, tmp, cache);
    return res.map(item => {
        let r = []
        item.map(a => {
            let str = ""
            for (let i = 0; i < n; i++)
                if (a === i) str += 'Q'
                else str += "."
            r.push(str)
        })
        return r
    })
}
console.log(solveNQueens(4));

N皇后II

在这里插入图片描述

/**
 * @param {number} n
 * @return {number}
 */
var totalNQueens = function(n) {
    // 当前填入的结果
    let tmp = new Array(n).fill(-1);
    
    let nums = 0;
    // 记录当前哪些位置不能放入皇后
    let cache = [];

    /**
     * 
     * @param {number} index 当前皇后在第几行 
     * @param {*} tmp 当前填入的结果
     * @param {*} cache 
     * @returns 
     */
    let dfs = function(index, tmp, cache) {
        // 最后一个皇后(结束)
        if (index == n) {
            ++nums;
            return;
        }

        for (let i = 0; i < n; i++) {
           //该位置不能放皇后
            if (cache.indexOf(index + "," + i) > -1) continue;
            
            let arr = [...tmp];
            // 放入皇后(在 第 index 行 第 i 列)
            arr[index] = i;

            // 判断填入的皇后是否符合条件
            let f = 0;
            for (let p = 0; p < n; p++) {
                for (let q = 0; q < n; q++) {
                    
                    if (cache.indexOf(p + ',' + q) == -1) {
                        // 计算当 在 第 index 行 第 i 列放入皇后后,其他哪些位置不能放入皇后
                        if (index == p || i == q || p -index == q - i || p+ q == index + i) {
                            cache.push(p + ',' + q);
                            f++;
                        }
                    }
                }
            }
            dfs(index + 1, arr, cache);
            while(f--) cache.pop(); // 删除标记
        }
    }
    dfs(0, tmp, cache);
    return nums;
};

2022-09-11

不同路径

在这里插入图片描述

/**
 * i 为行 j 为列
 * 从左上角 -> 右下角 由于每次移动只能 向右(j + 1) 或者 向下 (i + 1)
 * 因此到达 dp[i][j] 取决于
 *     (1)从右方向过来的(即从 dp[i][j - 1] 过来) 
 *     (2)从下方向过来的(即从 dp[i - 1][j] 过来) 
 * 故路径总和 dp[i][j] = dp[i][j - 1] + dp[i -1][j];
 */
var uniquePaths = function(m, n) {
    let dp = new Array(m).fill(new Array(n).fill(1));
   
    for (let i = 1; i < m; i++) {
        for (let j = 1; j < n; j++) {
            dp[i][j] = dp[i - 1][j] + dp[i][j - 1];
        }
    }

    return dp[m - 1][n - 1];
}
console.log(uniquePaths(3, 7));
不同路径II

在这里插入图片描述

// 道理跟上述一致,只不过需要判断该位置是否有障碍,若有障碍 则 dp[i][j] = 0;
var uniquePathsWithObstacles = function (obstacleGrid) {
  let m = obstacleGrid.length
  let n = obstacleGrid[0].length
  let dp = Array(m).fill().map(item => Array(n).fill(0))

  //初始化
  for (let i = 0; i < m && obstacleGrid[i][0] === 0; i++) {
    dp[i][0] = 1
  }
  for (let j = 0; j < n && obstacleGrid[0][j] === 0; j++) {
    dp[0][j] = 1
  }
  for (let i = 1; i < m; i++) {
    for (let j = 1; j < n; j++) {
      if (obstacleGrid[i][j] === 0) {
        dp[i][j] = dp[i - 1][j] + dp[i][j - 1]
      } else {
        dp[i][j] = 0
      }
    }
  }
  return dp[m - 1][n - 1]
};
console.log(uniquePathsWithObstacles([[0], [1]]))

2022-09-12

简化路径

在这里插入图片描述

var simplifyPath = function(path) {
  const arr = path.split('/');
  // 栈
  const stack = [];

  const len = arr.length;

  for (let i = 0; i < len; i++) {
    if (arr[i] === "" || arr[i] === ".") {
       // 当前目录
       continue;
    } else if (arr[i] === "..") {
       // 上一层目录
       stack.pop();
    } else {
       // 下一层目录
       stack.push(arr[i]);
    }
  }
  return '/' + stack.join('/');
}

console.log(simplifyPath("/home/"));
console.log(simplifyPath("/../"));
console.log(simplifyPath("/a/./b/../../c/"));
console.log(simplifyPath("/home//foo/"));
console.log(simplifyPath("/a/../../b/../c//.//"));
console.log(simplifyPath("/a//bc/d//././/.."));
矩阵置零

在这里插入图片描述

var setZeroes = function (matrix) {
  let row = matrix.length;
  let col = matrix[0].length;

  let rowArr = new Array(row).fill(false);
  let colArr = new Array(col).fill(false);

  // 将 matrix 中存在 0 的位置记录到 行数组(rowArr) 列数组(colArr)
  for (let i = 0; i < row; i++) {
    for (let j = 0; j < col; j++) {
      if (matrix[i][j] == 0) {
        rowArr[i] = true;
        colArr[j] = true;
      }
    }
  }

  // 更新
  for (let i = 0; i < row; i++) {
    for (let j = 0; j < col; j++) {
      if (rowArr[i] || colArr[j]) {
        matrix[i][j] = 0;
      }
    }
  }

  return matrix;
}
console.log(setZeroes([[1, 1, 1], [1, 0, 1], [1, 1, 1]]));

2022-09-13

合并区间

在这里插入图片描述

function getMerge(arr) {
    arr.sort((a, b) => {
        if (a[0] !== b[0]) {
            return a[0] - b[0];
        }
        return a[1] - b[1];
    });

    let len = arr.length;
    let ans = [];
    
    let start;
    let end;

    for (let i = 0; i < len; i++) {
        let s = arr[i][0];
        let e = arr[i][1];
      
        if (start == undefined) {
            start = s;
            end = e;
        } else if (s <= end) { // 当前的起始值在区间【start, end】 中
            end = Math.max(e, end);
        } else {
            // 创建新的区间
            let part = [start, end];
            ans.push(part);
            
            // 更新
            start = s;
            end = e;
        }
    }

    if (start !== undefined) {
        let part = [start, end]
        ans.push(part)
    }
    return ans;
}
let data = [
    [1,3],[2,6],[8,10],[15,18]
]
console.log(getMerge(data));
旋转链表

在这里插入图片描述

在这里插入图片描述

/**
 * Definition for singly-linked list.
 * function ListNode(val, next) {
 *     this.val = (val===undefined ? 0 : val)
 *     this.next = (next===undefined ? null : next)
 * }
 */
/**
 * @param {ListNode} head
 * @param {number} k
 * @return {ListNode}
 */
var rotateRight = function(head, k) {
    if (!head) return null;

    let cur = head;

    // 链表头尾相连
    let n = 1;
    while(cur.next) {
        cur = cur.next;
        n++;
    }
    cur.next = head;

    // 指针后移
    for (let i = 0; i < n - k % n; i++) {
         cur = cur.next;
    }
    head = cur.next;
    
    // 断开链表
    cur.next = null;
    return head;
};

2022-09-14

最小路径和

在这里插入图片描述

/**
 * i 为行 j 为列
 * 从左上角 -> 右下角 由于每次移动只能 向右(j + 1) 或者 向下 (i + 1)
 * 因此到达 dp[i][j] 取决于
 *     (1)从右方向过来的(即从 dp[i][j - 1] 过来) 
 *     (2)从下方向过来的(即从 dp[i - 1][j] 过来) 
 * 故路径总和 dp[i][j] = dp[i][j - 1] + dp[i -1][j];
 * 
 * 而针对此题需要改变的地方在于
 * (1)需要从最右下角 -> 左上角 进行动态规划,由此起始位置为 qp[grid.length - 1][grid[0].length - 1]
 * (2)dp[i][j] = dp[i][j + 1] + dp[i + 1][j];
 * (3)最终返回结果 dp[0][0]
 */
var minPathSum = function(grid) {
    let m = grid.length;
    let n = grid[0].length;

    let dp = new Array(m).fill(new Array(n).fill(1));

    for (let i = m - 1; i >= 0; i--) {
        for (let j = n - 1; j >= 0; j--) {
            if (i === m - 1) {  // 最后一行
               if (j === n - 1) {
                  // 到了右下角
                  dp[i][j] = grid[i][j];
                  console.log(dp);
               } else {
                  // 只能向右走 j + 1;
                  dp[i][j] = grid[i][j] + dp[i][j + 1];
               }
            } else if (j === n - 1) { // 最后一列
               // 只能向下走
               dp[i][j] = grid[i][j] + dp[i + 1][j];
            } else {
               dp[i][j] = grid[i][j] + Math.min(dp[i][j + 1], dp[i + 1][j]);
            }
        }
    }
    return dp[0][0];
}
console.log(minPathSum([[1,2,3],[4,5,6]]))
插入区间

在这里插入图片描述

/**
 * @param {number[][]} intervals
 * @param {number[]} newInterval
 * @return {number[][]}
 */
var insert = function(intervals, newInterval) {
   let n = intervals.length;
   let i = 0;
   let ans = [];

   // 将左侧没有包含新区间的加入到结果集中
   while (i < n && intervals[i][1] < newInterval[0]) {
       // 结束位小于新区间的开始位
       ans.push(intervals[i]);
       i++;
   }

   // 将包含区间合并
   if (i < n) {
       // 找到最小起始位
       newInterval[0] = Math.min(intervals[i][0], newInterval[0]);
       while (i < n && intervals[i][0] <= newInterval[1]) {
           newInterval[1] = Math.max(intervals[i][1], newInterval[1]);
           i++;
       }
   }
   ans.push(newInterval);
   
   // 将右侧区间填入
   while (i < n) {
       ans.push(intervals[i])
       i++;
   }

   return ans;
};

2022-09-15

搜索二维矩阵

在这里插入图片描述

var searchMatrix = function (matrix, target) {
  let row = matrix.length;
  let col = matrix[0].length;

  let startRow = row - 1;
  let startCol = 0;

  while (startRow >= 0 && startCol <= col) {
    if (matrix[startRow][startCol] == target) {
      return true;
    } else if (matrix[startRow][startCol] > target) {
      // 大于目标值 向上移
      startRow--;
    } else {
      // 小于目标值 向右移
      startCol++;
    }
  }

  return false;
}
let matrix = [
  [1, 4, 7, 11, 15],
  [2, 5, 8, 12, 19],
  [3, 6, 9, 16, 22],
  [10, 13, 14, 17, 24],
  [18, 21, 23, 26, 30]
]
console.log(searchMatrix(matrix, 8));
颜色分类

在这里插入图片描述

var sortColors = function (nums) {
  let swap = function (nums, i, j) {
    let temp = nums[i];
    nums[i] = nums[j];
    nums[j] = temp;
  }

  let n = nums.length;
  let p0 = 0;
  let p1 = 0;

  for (let i = 0; i < n; i++) {
    if (nums[i] === 1) {
      swap(nums, i, p1);
      p1++;
    } else if (nums[i] === 0) {
      swap(nums, i, p0);

      if (p0 < p1) swap(nums, i, p1);

      p0++;
      p1++;
    }
  }
  return nums;
}
let nums = [1, 2, 0, 2, 0, 1, 2, 1, 1, 0, 2, 1, 1, 1, 1, 2];
console.log(sortColors(nums));

2022-09-16

组合

在这里插入图片描述

var combine = function (n, k) {
  let res = [];
  /**
   * 
   * @param {number} cur 起始数值 
   * @param {*} n 结束数值
   * @param {*} k 第几次
   */
  var dfs = function (cur, n, k, temp) {
    // 剪枝
    if (temp.length == k) {
      res.push([...temp]);
      return;
    }
    for (let i = cur; i <= n; i++) {
      temp.push(i);
      dfs(i + 1, n, k, temp);
      temp.pop();
    }
  }
  dfs(1, n, k, []);
  return res;
}
console.log(combine(6, 3));
子集

在这里插入图片描述

var subsets = function (nums) {
  // 当前结果集
  let res = [[]];
  for (let num of nums) {
    let tmp = [];
    // 遍历之前存在的结果集
    for (let before of res) {
      tmp.push(before.concat(num))
    }

    res = res.concat(tmp);
    console.log("从集合中取出数值", num, "此时集合为", tmp, "进行合并后", res);
  }
  return res;
}
console.log(subsets([3, 2, 1]));

2022-09-18


2022-09-19

排列序列

在这里插入图片描述

比如n = 4,那么以1开头的单词有 3 * 2 * 1 个;n = 3,以1开头的单词有 2 * 1个,依次类推,只要得出 k 是当前阶乘的多少倍,那么就获取剩下的当中的第几个单词。

/**
 * @param {number} n
 * @param {number} k
 * @return {string}
 */
var getPermutation = function(n, k) {
  let m = 1;
  k = k - 1;
  for (let i = 2; i < n; i++) m *= i;

  let a = [];
  for (let i = 1; i <= n; i++) a.push(i)

  let s = []
  for (let i = 0; i < n; i++) {
    let t = k / m | 0
    s[i] = a[t]
    a.splice(t, 1)
    k %= m
    m /= (n - i - 1)
  }
  return s.join("");
};
单词搜索

在这里插入图片描述

/**
 * @param {character[][]} board
 * @param {string} word
 * @return {boolean}
 */
var exist = function(board, word) {
   let row = board.length;
   let col = board[0].length;

   let dfs = (i, j, len) => {
       if (len == word.length) return true;
       // 越界
       if (i >= row || j >= col || j < 0 || i < 0) return false;

       if (board[i][j] !== word.charAt(len)) return false;

       let pre = board[i][j];
       board[i][j] = '.'; // 记录改为已经被匹配过了
       
       // 从四个方向继续查找
       let res = dfs(i + 1, j, len + 1) || dfs(i, j + 1, len + 1) || dfs(i - 1, j, len + 1) || dfs(i, j -1, len + 1);
       board[i][j] = pre;
       return res;
   }

   for (let i = 0; i < row; i++) {
       for (let j = 0; j < col; j++) {
           if (dfs(i, j, 0)) return true; 
       }
   }
   return false;
};

2022-09-20

删除有序数组中的重复项||

在这里插入图片描述

let removeDuplicates = function(nums) {
    if (nums.length <= 2) return nums.length;

    let len = 2;
    for (let i = 2; i < nums.length; i++) {
        if (nums[i] != nums[len - 2]) {
            nums[len] = nums[i];
            len++;
        }
    }
    return len;
}
console.log(removeDuplicates([1, 1, 1, 2, 2, 3]));
子集II

在这里插入图片描述

/**
 * @param {number[]} nums
 * @return {number[][]}
 */
var subsetsWithDup = function (nums) {
  const result = [];
  nums.sort((a, b) => {
    return a - b;
  });

  let backtrack = (start, curr) => {
    result.push([...curr]);
    for (let i = start; i < nums.length; i++) {
      if (i > start && nums[i] == nums[i - 1]) {
        continue;
      }

      curr.push(nums[i]);
      backtrack(i + 1, curr);
      curr.pop();
    }
  }
  backtrack(0, []);
  return result;
};

2022-09-21

删除排序链表中的重复元素II

在这里插入图片描述

var deleteDuplicates = function (head) {
  if (!head) return head;

  // 记录链表头结点地址
  const dummy = new ListNode(0, head);

  let cur = dummy;
  // 第一个结点和第二个结点
  while (cur.next && cur.next.next) {
    // 第一个结点和第二结点值相等
    if (cur.next.val == cur.next.next.val) {
      const x = cur.next.val;

      // 指针指向下个与 x 值不不相等的值地址
      while (cur.next && cur.next.val === x) {
        cur.next = cur.next.next;
      }
    } else {
      // 指针继续向前
      cur = cur.next;
    }
  }
  // dummy.next 指向的是 head 的地址
  return dummy.next;
} 
单词子集

在这里插入图片描述

/**
 * @param {string[]} words1
 * @param {string[]} words2
 * @return {string[]}
 */
var wordSubsets = function (words1, words2) {
  const B = new Array(26).fill(0);
  words2.forEach(w => {
    const tmp = new Array(26).fill(0);
    for (const c of w) {
      const idx = c.charCodeAt() - 97
      if (tmp[idx]++ === B[idx]) B[idx]++;
    }
  });
  return words1.filter(w => {
    const tmp = B.slice();
    for (const c of w) {
      const idx = c.charCodeAt() - 97;
      if (tmp[idx] > 0) tmp[idx]--;
    }
    return tmp.every(cnt => cnt === 0);
  })
};

2022-09-22

柱状图中最大的矩阵

在这里插入图片描述

var largestRectangleArea = function (heights) {
  let large = 0;
  let shift = [{ index: -1, height: -1 }];
  for (let i = 0; i < heights.length; i++) {
    // 队列中最后一个元素为非初始化元素
    while (shift[shift.length - 1].height !== -1 && shift[shift.length - 1].height > heights[i]) {
      const pop = shift.pop();
      large = Math.max(large, pop.height * (i - 1 - shift[shift.length - 1].index));
    }
    shift.push({ index: i, height: heights[i] });
  }
  const top = shift[shift.length - 1].index;
  // 队列中最后一个元素为非初始化元素
  while (shift[shift.length - 1].height !== -1) {
    const pop = shift.pop();
    large = Math.max(large, pop.height * (top - shift[shift.length - 1].index));
  }
  return large
};
单词拆分

在这里插入图片描述

var wordBreak = function (s, wordDict) {
  const slen = s.length;
  const set = new Set(wordDict);
  let arr = new Array(slen + 1).fill(false);

  arr[0] = true;

  for (let i = 1; i <= slen; i++) {
    for (let j = 0; j < i; j++) {
      if (arr[j] && set.has(s.substr(j, i - j))) {
        arr[i] = true;
        break;
      }
    }
  }
  return arr[slen];
}
let s = `applepenapple`;
let wordDict = ['apple', 'pen'];
console.log(wordBreak(s, wordDict));

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

海面有风

您的鼓励将是我前进的动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值