最近一年坚持做题了133天!
11月
12月
1月
2月
3月
4月
5月
6月
7月
8月
9月
10月
Less
More
题目类型:全部中心扩展二分查找二叉树分治动态规划双指针哈希表回溯图堆字符串广度优先搜索数学数组栈滑动窗口矩阵贪心递归链表队列攻克207道题目
130.被围绕的区域中等
2026-09-14#矩阵
问题: 给你一个 m x n 的矩阵 board ,由若干字符 'X' 和 'O' 组成, 捕获 所有 被围绕的区域 : 连接: 一个单元格与水平或垂直方向上相邻的单元格连接。 区域:连接所有 'O' 的单元格来形成一个区域。 围绕: 如果一个区域中的所有 'O' 单元格都不在棋盘的边缘,则该区域被包围。这样的区域 完全 被 'X' 单元格包围。 通过 原地 将输入矩阵中的所有 'O' 替换为 'X' 来 捕获被围绕的区域 。你不需要返回任何值。 示例 1: 输入: board = [['X','X','X','X'],['X','O','O','X'],['X','X','O','X'],['X','O','X','X']] 输出: [['X','X','X','X'],['X','X','X','X'],['X','X','X','X'],['X','O','X','X']] 解释: 在上图中,底部的区域没有被捕获,因为它在 board 的边缘并且不能被围绕。 示例 2: 输入: board = [['X']] 输出: [['X']] 回答: 遍历四个边界,如果为O的话代表不被围绕 var solve = function(board) { if (!board.length) return []; let m = board.length; let n = board[0].length; var dfs = function(i, j) { if (i < 0 || i >= m || j < 0 || j >= n || board[i][j] != 'O') return; board[i][j] = '#'; dfs(i - 1, j); dfs(i + 1, j); dfs(i, j - 1); dfs(i, j + 1); } //从上下边界进行遍历 for (let j = 0; j < n; j++) { dfs(0, j); dfs(m - 1, j) } //从左右边界进行遍历 for (let i = 0; i < m; i++) { dfs(i, 0); dfs(i, n - 1); } for (let i = 0; i < m; i++) { for (let j = 0; j < n; j++) { if (board[i][j] == 'O') { board[i][j] = 'X'; } else if (board[i][j] == '#') { board[i][j] = 'O' } } } return board; };
119.杨辉三角II简单
2026-09-10#动态规划
问题: 给定一个非负索引 rowIndex ,返回「杨辉三角」的第 rowIndex 行。 在「杨辉三角」中,每个数是它左上方和右上方的数的和。 示例 1: 输入: rowIndex = 3 输出: [1,3,3,1] 示例 2: 输入: rowIndex = 0 输出: [1] 示例 3: 输入: rowIndex = 1 输出: [1,1] 回答: var getRow = function(rowIndex) { let res = [1]; for (let i = 1; i <= rowIndex; i++) { let cur = new Array(i + 1).fill(1); for (let j = 1; j < i; j++) { cur[j] = res[j - 1] + res[j]; } res = cur; } return res; };
118.杨辉三角简单
2026-09-10#数组#动态规划
问题: 给定一个非负整数 numRows, 生成「杨辉三角」的前 numRows 行。 在 「杨辉三角」 中,每个数是它左上方和右上方的数的和。 示例 1: 输入: numRows = 5 输出: [[1],[1,1],[1,2,1],[1,3,3,1],[1,4,6,4,1]] 示例 2: 输入: numRows = 1 输出: [[1]] 回答: var generate = function(numRows) { let res = []; for (let i = 0; i < numRows; i++) { let cur = new Array(i + 1).fill(1); for (let j = 1; j < i; j++) { cur[j] = res[i - 1][j - 1] + res[i - 1][j]; } res.push(cur); } return res; };
107. 二叉树的层序遍历 II中等
2026-09-08#二叉树
问题: 给你二叉树的根节点 root ,返回其节点值 自底向上的层序遍历 。 (即按从叶子节点所在层到根节点所在的层,逐层从左向右遍历) 示例 1: 输入:root = [3,9,20,null,null,15,7] 输出:[[15,7],[9,20],[3]] 示例 2: 输入:root = [1] 输出:[[1]] 示例 3: 输入:root = [] 输出:[] 回答: 正常的层级遍历,最后反转数组 var levelOrderBottom = function(root) { if (!root) return []; let res = []; let queue = [root]; while (queue.length) { let len = queue.length; let current = []; for (let i = 0; i < len; i++) { let node = queue.shift(); current.push(node.val); if (node.left) queue.push(node.left); if (node.right) queue.push(node.right); } res.push(current); } return res.reverse(); };
90.子集II中等
2026-09-07#回溯
问题: 给你一个整数数组 nums ,其中可能包含重复元素,请你返回该数组所有可能的 子集 (幂集)。 解集 不能 包含重复的子集。返回的解集中,子集可以按 任意顺序 排列。 示例 1: 输入:nums = [1,2,2] 输出:[[],[1],[1,2],[1,2,2],[2],[2,2]] 示例 2: 输入:nums = [0] 输出:[[],[0]] 回答: var subsetsWithDup = function(nums) { //先排序,使重复元素相邻 nums = nums.sort((a, b) => a - b); let res = []; let path = []; let len = nums.length; var backTrack = function(path, index) { res.push([...path]); for (let i = index; i < len; i++) { //当前层重复元素不再收集 if (i > index && nums[i] == nums[i - 1]) { continue; } path.push(nums[i]); backTrack(path, i + 1); path.pop(); } } backTrack([], 0) return res; };
67. 二进制求和简单
2026-09-04#数学
问题: 给你两个二进制字符串 a 和 b ,以二进制字符串的形式返回它们的和。 示例 1: 输入:a = "11", b = "1" 输出:"100" 示例 2: 输入:a = "1010", b = "1011" 输出:"10101" 回答: var addBinary = function(a, b) { let m = a.length - 1; let n = b.length - 1; let res = ''; let add = 0; while (m >= 0 || n >= 0 || add > 0) { let val1 = a[m] ? Number(a[m]) : 0; let val2 = b[n] ? Number(b[n]) : 0; let sum = val1 + val2 + add; add = Math.floor(sum / 2); let cur = sum % 2; res = cur.toString() + res; m--; n--; } return res; };
131.分割回文串中等
2026-07-24#回溯
问题: 给你一个字符串 s ,请你将 s 分割成一些 子串 ,使每个子串都是 回文串 。返回 s 所有可能的分割方案。 示例 1: 输入:s = "aab" 输出:[["a","a","b"],["aa","b"]] 示例 2: 输入:s = "a" 输出:[["a"]] 回答: var partition = function(s) { const n = s.length; const result = []; const path = []; // dp[i][j] 表示 s[i..j] 是否是回文 const dp = Array.from({ length: n }, () => Array(n).fill(false)); // 从短到长递推 for (let j = 0; j < n; j++) { for (let i = 0; i <= j; i++) { if (s[i] === s[j] && (j - i <= 2 || dp[i + 1][j - 1])) { dp[i][j] = true; } } } function backtrack(start) { if (start === n) { result.push([...path]); return; } for (let end = start; end < n; end++) { if (dp[start][end]) { path.push(s.slice(start, end + 1)); backtrack(end + 1); path.pop(); } } } backtrack(0); return result; };
73.矩阵置零中等
2026-07-06#矩阵
问题: 给定一个 m x n 的矩阵,如果一个元素为 0 ,则将其所在行和列的所有元素都设为 0 。请使用 原地 算法 。 示例 1: 输入:matrix = [[1,1,1],[1,0,1],[1,1,1]] 输出:[[1,0,1],[0,0,0],[1,0,1]] 示例 2: 输入:matrix = [[0,1,2,0],[3,4,5,2],[1,3,1,5]] 输出:[[0,0,0,0],[0,4,5,0],[0,3,1,0]] 回答: function setZeroes(matrix) { const m = matrix.length; const n = matrix[0].length; let firstRowHasZero = false; let firstColHasZero = false; // 检查第一行是否有 0 for (let j = 0; j < n; j++) { if (matrix[0][j] === 0) { firstRowHasZero = true; break; } } // 检查第一列是否有 0 for (let i = 0; i < m; i++) { if (matrix[i][0] === 0) { firstColHasZero = true; break; } } // 用第一行和第一列做标记 for (let i = 1; i < m; i++) { for (let j = 1; j < n; j++) { if (matrix[i][j] === 0) { matrix[i][0] = 0; matrix[0][j] = 0; } } } // 根据标记置零(不包含第一行、第一列) for (let i = 1; i < m; i++) { for (let j = 1; j < n; j++) { if (matrix[i][0] === 0 || matrix[0][j] === 0) { matrix[i][j] = 0; } } } // 处理第一行 if (firstRowHasZero) { for (let j = 0; j < n; j++) { matrix[0][j] = 0; } } // 处理第一列 if (firstColHasZero) { for (let i = 0; i < m; i++) { matrix[i][0] = 0; } } }
57.插入区间中等
2026-07-05#数组
问题: 给你一个 无重叠的 , 按照区间起始端点排序的区间列表 intervals ,其中 intervals[i] = [starti, endi] 表示第 i 个区间的开始和结束,并且 intervals 按照 starti 升序排列。同样给定一个区间 newInterval = [start, end] 表示另一个区间的开始和结束。 在 intervals 中插入区间 newInterval ,使得 intervals 依然按照 starti 升序排列,且区间之间不重叠(如果有必要的话,可以合并区间)。 返回插入之后的 intervals 。 注意 你不需要原地修改 intervals 。你可以创建一个新数组然后返回它。 示例 1: 输入:intervals = [[1,3],[6,9]], newInterval = [2,5] 输出:[[1,5],[6,9]] 示例 2: 输入:intervals = [[1,2],[3,5],[6,7],[8,10],[12,16]], newInterval = [4,8] 输出:[[1,2],[3,10],[12,16]] 解释:这是因为新的区间 [4,8] 与 [3,5],[6,7],[8,10] 重叠 回答: var insert = function(intervals, newInterval) { const result = []; let i = 0; const n = intervals.length; // 第一阶段:新区间左边的区间 while (i < n && intervals[i][1] < newInterval[0]) { result.push(intervals[i]); i++; } // 第二阶段:合并所有与新区间重叠的区间 while (i < n && intervals[i][0] <= newInterval[1]) { newInterval[0] = Math.min(newInterval[0], intervals[i][0]); newInterval[1] = Math.max(newInterval[1], intervals[i][1]); i++; } result.push(newInterval); // 第三阶段:新区间右边的区间 while (i < n) { result.push(intervals[i]); i++; } return result; };
N皇后困难
2026-06-21#回溯
问题: 按照国际象棋的规则,皇后可以攻击与之处在同一行或同一列或同一斜线上的棋子。 n 皇后问题 研究的是如何将 n 个皇后放置在 n×n 的棋盘上,并且使皇后彼此之间不能相互攻击。 给你一个整数 n ,返回所有不同的 n 皇后问题 的解决方案。 每一种解法包含一个不同的 n 皇后问题 的棋子放置方案,该方案中 'Q' 和 '.' 分别代表了皇后和空位。 示例 1: 输入:n = 4 输出:[[".Q..","...Q","Q...","..Q."],["..Q.","Q...","...Q",".Q.."]] 解释:如上图所示,4 皇后问题存在两个不同的解法。 示例 2: 输入:n = 1 输出:[["Q"]] 回答: function solveNQueens(n) { const result = []; // 用三个 Set 分别记录被占用的列、主对角线、副对角线 const cols = new Set(); const diag1 = new Set(); // row - col const diag2 = new Set(); // row + col // board 记录每一行皇后所在的列索引 const board = new Array(n); function backtrack(row) { // 递归终止:所有行都放完了 if (row === n) { // 将 board 转换成题目要求的字符串数组格式 result.push(buildBoard(board)); return; } // 尝试当前行的每一列 for (let col = 0; col < n; col++) { const d1 = row - col; const d2 = row + col; // 检查是否冲突 if (cols.has(col) || diag1.has(d1) || diag2.has(d2)) { continue; } // 做选择 board[row] = col; cols.add(col); diag1.add(d1); diag2.add(d2); // 递归下一行 backtrack(row + 1); // 撤销选择(回溯) cols.delete(col); diag1.delete(d1); diag2.delete(d2); // board[row] 下一轮会被覆盖 } } // 辅助函数:将 board 转为 ['Q..', '...'] 格式 function buildBoard(board) { const result = []; for (let i = 0; i < n; i++) { const row = new Array(n).fill('.'); row[board[i]] = 'Q'; result.push(row.join('')); } return result; } backtrack(0); return result; }
  • 1
  • 2
  • 3
  • 4
  • 21
assistant