From 5c0e88fde0fa4bbaa0e5aedc016c8c9740ee0a9c Mon Sep 17 00:00:00 2001 From: ITCharge Date: Tue, 15 Jul 2025 09:13:42 +0800 Subject: [PATCH 1/2] =?UTF-8?q?=E6=9B=B4=E6=94=B9=E9=A2=98=E7=9B=AE?= =?UTF-8?q?=E9=93=BE=E6=8E=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/solutions/Interviews/bracket-lcci.md | 45 --------- docs/solutions/Interviews/calculator-lcci.md | 66 ------------- docs/solutions/Interviews/color-fill-lcci.md | 66 ------------- .../solutions/Interviews/eight-queens-lcci.md | 77 --------------- .../Interviews/factorial-zeros-lcci.md | 33 ------- .../Interviews/first-common-ancestor-lcci.md | 61 ------------ .../Interviews/group-anagrams-lcci.md | 42 -------- .../implement-queue-using-stacks-lcci.md | 74 --------------- docs/solutions/Interviews/index.md | 32 ------- .../intersection-of-two-linked-lists-lcci.md | 54 ----------- .../kth-node-from-end-of-list-lcci.md | 38 -------- .../legal-binary-search-tree-lcci.md | 46 --------- .../Interviews/linked-list-cycle-lcci.md | 47 --------- .../solutions/Interviews/longest-word-lcci.md | 95 ------------------- docs/solutions/Interviews/min-stack-lcci.md | 59 ------------ .../Interviews/minimum-height-tree-lcci.md | 34 ------- .../solutions/Interviews/multi-search-lcci.md | 80 ---------------- .../Interviews/number-of-2s-in-range-lcci.md | 85 ----------------- .../Interviews/palindrome-linked-list-lcci.md | 32 ------- .../Interviews/paths-with-sum-lcci.md | 45 --------- .../Interviews/permutation-i-lcci.md | 46 --------- .../Interviews/permutation-ii-lcci.md | 55 ----------- docs/solutions/Interviews/power-set-lcci.md | 35 ------- .../Interviews/rotate-matrix-lcci.md | 67 ------------- docs/solutions/Interviews/smallest-k-lcci.md | 73 -------------- .../Interviews/sorted-matrix-search-lcci.md | 90 ------------------ .../solutions/Interviews/sorted-merge-lcci.md | 72 -------------- docs/solutions/Interviews/successor-lcci.md | 39 -------- docs/solutions/Interviews/sum-lists-lcci.md | 47 --------- .../Interviews/words-frequency-lcci.md | 78 --------------- docs/solutions/Interviews/zero-matrix-lcci.md | 70 -------------- 31 files changed, 1783 deletions(-) delete mode 100644 docs/solutions/Interviews/bracket-lcci.md delete mode 100644 docs/solutions/Interviews/calculator-lcci.md delete mode 100644 docs/solutions/Interviews/color-fill-lcci.md delete mode 100644 docs/solutions/Interviews/eight-queens-lcci.md delete mode 100644 docs/solutions/Interviews/factorial-zeros-lcci.md delete mode 100644 docs/solutions/Interviews/first-common-ancestor-lcci.md delete mode 100644 docs/solutions/Interviews/group-anagrams-lcci.md delete mode 100644 docs/solutions/Interviews/implement-queue-using-stacks-lcci.md delete mode 100644 docs/solutions/Interviews/index.md delete mode 100644 docs/solutions/Interviews/intersection-of-two-linked-lists-lcci.md delete mode 100644 docs/solutions/Interviews/kth-node-from-end-of-list-lcci.md delete mode 100644 docs/solutions/Interviews/legal-binary-search-tree-lcci.md delete mode 100644 docs/solutions/Interviews/linked-list-cycle-lcci.md delete mode 100644 docs/solutions/Interviews/longest-word-lcci.md delete mode 100644 docs/solutions/Interviews/min-stack-lcci.md delete mode 100644 docs/solutions/Interviews/minimum-height-tree-lcci.md delete mode 100644 docs/solutions/Interviews/multi-search-lcci.md delete mode 100644 docs/solutions/Interviews/number-of-2s-in-range-lcci.md delete mode 100644 docs/solutions/Interviews/palindrome-linked-list-lcci.md delete mode 100644 docs/solutions/Interviews/paths-with-sum-lcci.md delete mode 100644 docs/solutions/Interviews/permutation-i-lcci.md delete mode 100644 docs/solutions/Interviews/permutation-ii-lcci.md delete mode 100644 docs/solutions/Interviews/power-set-lcci.md delete mode 100644 docs/solutions/Interviews/rotate-matrix-lcci.md delete mode 100644 docs/solutions/Interviews/smallest-k-lcci.md delete mode 100644 docs/solutions/Interviews/sorted-matrix-search-lcci.md delete mode 100644 docs/solutions/Interviews/sorted-merge-lcci.md delete mode 100644 docs/solutions/Interviews/successor-lcci.md delete mode 100644 docs/solutions/Interviews/sum-lists-lcci.md delete mode 100644 docs/solutions/Interviews/words-frequency-lcci.md delete mode 100644 docs/solutions/Interviews/zero-matrix-lcci.md diff --git a/docs/solutions/Interviews/bracket-lcci.md b/docs/solutions/Interviews/bracket-lcci.md deleted file mode 100644 index afb671f1..00000000 --- a/docs/solutions/Interviews/bracket-lcci.md +++ /dev/null @@ -1,45 +0,0 @@ -# [面试题 08.09. 括号](https://leetcode.cn/problems/bracket-lcci/) - -- 标签:字符串、动态规划、回溯 -- 难度:中等 - -## 题目链接 - -- [面试题 08.09. 括号 - 力扣](https://leetcode.cn/problems/bracket-lcci/) - -## 题目大意 - -给定一个整数 `n`。 - -要求:生成所有有可能且有效的括号组合。 - -## 解题思路 - -通过回溯算法生成所有答案。为了生成的括号组合是有效的,回溯的时候,使用一个标记变量 `symbol` 来表示是否当前组合是否成对匹配。 - -如果在当前组合中增加一个 `(`,则 `symbol += 1`,如果增加一个 `)`,则 `symbol -= 1`。显然只有在 `symbol < n` 的时候,才能增加 `(`,在 `symbol > 0` 的时候,才能增加 `)`。 - -如果最终生成 `2 * n` 的括号组合,并且 `symbol == 0`,则说明当前组合是有效的,将其加入到最终答案数组中。 - -最终输出最终答案数组。 - -## 代码 - -```python -class Solution: - def generateParenthesis(self, n: int) -> List[str]: - def backtrack(parenthesis, symbol, index): - if n * 2 == index: - if symbol == 0: - parentheses.append(parenthesis) - else: - if symbol < n: - backtrack(parenthesis + '(', symbol + 1, index + 1) - if symbol > 0: - backtrack(parenthesis + ')', symbol - 1, index + 1) - - parentheses = list() - backtrack("", 0, 0) - return parentheses -``` - diff --git a/docs/solutions/Interviews/calculator-lcci.md b/docs/solutions/Interviews/calculator-lcci.md deleted file mode 100644 index ce90dafb..00000000 --- a/docs/solutions/Interviews/calculator-lcci.md +++ /dev/null @@ -1,66 +0,0 @@ -# [面试题 16.26. 计算器](https://leetcode.cn/problems/calculator-lcci/) - -- 标签:栈、数学、字符串 -- 难度:中等 - -## 题目链接 - -- [面试题 16.26. 计算器 - 力扣](https://leetcode.cn/problems/calculator-lcci/) - -## 题目大意 - -给定一个包含正整数、加(`+`)、减(`-`)、乘(`*`)、除(`/`)的算出表达式(括号除外)。表达式仅包含非负整数,`+`、`-`、`*`、`/` 四种运算符和空格 ` `。整数除法仅保留整数部分。 - -要求:计算其结果。 - -## 解题思路 - -计算表达式中,乘除运算优先于加减运算。我们可以先进行乘除运算,再将进行乘除运算后的整数值放入原表达式中相应位置,再依次计算加减。 - -可以考虑使用一个栈来保存进行乘除运算后的整数值。正整数直接压入栈中,负整数,则将对应整数取负号,再压入栈中。这样最终计算结果就是栈中所有元素的和。 - -具体做法: - -- 遍历字符串 s,使用变量 op 来标记数字之前的运算符,默认为 `+`。 -- 如果遇到数字,继续向后遍历,将数字进行累积,得到完整的整数 num。判断当前 op 的符号。 - - 如果 op 为 `+`,则将 num 压入栈中。 - - 如果 op 为 `-`,则将 -num 压入栈中。 - - 如果 op 为 `*`,则将栈顶元素 top 取出,计算 top * num,并将计算结果压入栈中。 - - 如果 op 为 `/`,则将栈顶元素 top 取出,计算 int(top / num),并将计算结果压入栈中。 -- 如果遇到 `+`、`-`、`*`、`/` 操作符,则更新 op。 -- 最后将栈中整数进行累加,并返回结果。 - -## 代码 - -```python -class Solution: - def calculate(self, s: str) -> int: - size = len(s) - stack = [] - op = '+' - index = 0 - while index < size: - if s[index] == ' ': - index += 1 - continue - if s[index].isdigit(): - num = ord(s[index]) - ord('0') - while index + 1 < size and s[index + 1].isdigit(): - index += 1 - num = 10 * num + ord(s[index]) - ord('0') - if op == '+': - stack.append(num) - elif op == '-': - stack.append(-num) - elif op == '*': - top = stack.pop() - stack.append(top * num) - elif op == '/': - top = stack.pop() - stack.append(int(top / num)) - elif s[index] in "+-*/": - op = s[index] - index += 1 - return sum(stack) -``` - diff --git a/docs/solutions/Interviews/color-fill-lcci.md b/docs/solutions/Interviews/color-fill-lcci.md deleted file mode 100644 index 0581382e..00000000 --- a/docs/solutions/Interviews/color-fill-lcci.md +++ /dev/null @@ -1,66 +0,0 @@ -# [面试题 08.10. 颜色填充](https://leetcode.cn/problems/color-fill-lcci/) - -- 标签:深度优先搜索、广度优先搜索、数组、矩阵 -- 难度:简单 - -## 题目链接 - -- [面试题 08.10. 颜色填充 - 力扣](https://leetcode.cn/problems/color-fill-lcci/) - -## 题目大意 - -给定一个二维整数矩阵 `image`,其中 `image[i][j]` 表示矩阵第 `i` 行、第 `j` 列上网格块的颜色值。再给定一个起始位置 `(sr, sc)`,以及一个目标颜色 `newColor`。 - -要求:对起始位置 `(sr, sc)` 所在位置周围区域填充颜色为 `newColor`。并返回填充后的图像 `image`。 - -- 周围区域:颜色相同且在上、下、左、右四个方向上存在相连情况的若干元素。 - -## 解题思路 - -深度优先搜索。使用二维数组 `visited` 标记访问过的节点。遍历上、下、左、右四个方向上的点。如果下一个点位置越界,或者当前位置与下一个点位置颜色不一样,则对该节点进行染色。 - -在遍历的过程中注意使用 `visited` 标记访问过的节点,以免重复遍历。 - -## 代码 - -```python -class Solution: - directs = [(0, 1), (0, -1), (1, 0), (-1, 0)] - - def dfs(self, image, i, j, origin_color, color, visited): - rows, cols = len(image), len(image[0]) - - for direct in self.directs: - new_i = i + direct[0] - new_j = j + direct[1] - - # 下一个位置越界,则当前点在边界,对其进行着色 - if new_i < 0 or new_i >= rows or new_j < 0 or new_j >= cols: - image[i][j] = color - continue - - # 如果访问过,则跳过 - if visited[new_i][new_j]: - continue - - # 如果下一个位置颜色与当前颜色相同,则继续搜索 - if image[new_i][new_j] == origin_color: - visited[new_i][new_j] = True - self.dfs(image, new_i, new_j, origin_color, color, visited) - # 下一个位置颜色与当前颜色不同,则当前位置为连通区域边界,对其进行着色 - else: - image[i][j] = color - - def floodFill(self, image: List[List[int]], sr: int, sc: int, newColor: int) -> List[List[int]]: - if not image: - return image - - rows, cols = len(image), len(image[0]) - visited = [[False for _ in range(cols)] for _ in range(rows)] - visited[sr][sc] = True - - self.dfs(image, sr, sc, image[sr][sc], newColor, visited) - - return image -``` - diff --git a/docs/solutions/Interviews/eight-queens-lcci.md b/docs/solutions/Interviews/eight-queens-lcci.md deleted file mode 100644 index d1447849..00000000 --- a/docs/solutions/Interviews/eight-queens-lcci.md +++ /dev/null @@ -1,77 +0,0 @@ -# [面试题 08.12. 八皇后](https://leetcode.cn/problems/eight-queens-lcci/) - -- 标签:数组、回溯 -- 难度:困难 - -## 题目链接 - -- [面试题 08.12. 八皇后 - 力扣](https://leetcode.cn/problems/eight-queens-lcci/) - -## 题目大意 - -- n 皇后问题:将 n 个皇后放置在 `n * n` 的棋盘上,并且使得皇后彼此之间不能攻击。 -- 皇后彼此不能相互攻击:指的是任何两个皇后都不能处于同一条横线、纵线或者斜线上。 - -现在给定一个整数 `n`,返回所有不同的「n 皇后问题」的解决方案。每一种解法包含一个不同的「n 皇后问题」的棋子放置方案,该方案中的 `Q` 和 `.` 分别代表了皇后和空位。 - -## 解题思路 - -经典的回溯问题。使用 `chessboard` 来表示棋盘,`Q` 代表皇后,`.` 代表空位,初始都为 `.`。然后使用 `res` 存放最终答案。 - -先定义棋盘合理情况判断方法,判断同一条横线、纵线或者斜线上是否存在两个以上的皇后。 - -再定义回溯方法,从第一行开始进行遍历。 - -- 如果当前行 `row` 等于 `n`,则当前棋盘为一个可行方案,将其拼接加入到 `res` 数组中。 -- 遍历 `[0, n]` 列元素,先验证棋盘是否可行,如果可行: - - 将当前行当前列尝试换为 `Q`。 - - 然后继续递归下一行。 - - 再将当前行回退为 `.`。 -- 最终返回 `res` 数组。 - -## 代码 - -```python -class Solution: - res = [] - def backtrack(self, n: int, row: int, chessboard: List[List[str]]): - if row == n: - temp_res = [] - for temp in chessboard: - temp_str = ''.join(temp) - temp_res.append(temp_str) - self.res.append(temp_res) - return - for col in range(n): - if self.isValid(n, row, col, chessboard): - chessboard[row][col] = 'Q' - self.backtrack(n, row + 1, chessboard) - chessboard[row][col] = '.' - - def isValid(self, n: int, row: int, col: int, chessboard: List[List[str]]): - for i in range(row): - if chessboard[i][col] == 'Q': - return False - - i, j = row - 1, col - 1 - while i >= 0 and j >= 0: - if chessboard[i][j] == 'Q': - return False - i -= 1 - j -= 1 - i, j = row - 1, col + 1 - while i >= 0 and j < n: - if chessboard[i][j] == 'Q': - return False - i -= 1 - j += 1 - - return True - - def solveNQueens(self, n: int) -> List[List[str]]: - self.res.clear() - chessboard = [['.' for _ in range(n)] for _ in range(n)] - self.backtrack(n, 0, chessboard) - return self.res -``` - diff --git a/docs/solutions/Interviews/factorial-zeros-lcci.md b/docs/solutions/Interviews/factorial-zeros-lcci.md deleted file mode 100644 index 6f3f8770..00000000 --- a/docs/solutions/Interviews/factorial-zeros-lcci.md +++ /dev/null @@ -1,33 +0,0 @@ -# [面试题 16.05. 阶乘尾数](https://leetcode.cn/problems/factorial-zeros-lcci/) - -- 标签:数学 -- 难度:简单 - -## 题目链接 - -- [面试题 16.05. 阶乘尾数 - 力扣](https://leetcode.cn/problems/factorial-zeros-lcci/) - -## 题目大意 - -给定一个整数 `n`。 - -要求:计算 `n` 的阶乘中尾随零的数量。 - -注意:$0 <= n <= 10^4$。 - -## 解题思路 - -阶乘中,末尾 `0` 的来源只有 `2 * 5`。所以尾随 `0` 的个数为 `2` 的倍数个数和 `5` 的倍数个数的最小值。又因为 `2 < 5`,`2` 的倍数个数肯定小于等于 `5` 的倍数,所以直接统计 `5` 的倍数个数即可。 - -## 代码 - -```python -class Solution: - def trailingZeroes(self, n: int) -> int: - count = 0 - while n > 0: - count += n // 5 - n = n // 5 - return count -``` - diff --git a/docs/solutions/Interviews/first-common-ancestor-lcci.md b/docs/solutions/Interviews/first-common-ancestor-lcci.md deleted file mode 100644 index f1fb498b..00000000 --- a/docs/solutions/Interviews/first-common-ancestor-lcci.md +++ /dev/null @@ -1,61 +0,0 @@ -# [面试题 04.08. 首个共同祖先](https://leetcode.cn/problems/first-common-ancestor-lcci/) - -- 标签:树、深度优先搜索、二叉树 -- 难度:中等 - -## 题目链接 - -- [面试题 04.08. 首个共同祖先 - 力扣](https://leetcode.cn/problems/first-common-ancestor-lcci/) - -## 题目大意 - -给定一个二叉树,要求找到该树中指定节点 `p`、`q` 的最近公共祖先: - -- 祖先:若节点 `p` 在节点 `node` 的左子树或右子树中,或者 `p = node`,则称 `node` 是 `p` 的祖先。 - -- 最近公共祖先:对于树的两个节点 `p`、`q`,最近公共祖先表示为一个节点 `lca_node`,满足 `lca_node` 是 `p`、`q` 的祖先且 `lca_node` 的深度尽可能大(一个节点也可以是自己的祖先)。 - -## 解题思路 - -设 `lca_node` 为节点 `p`、`q` 的最近公共祖先。则 `lca_node` 只能是下面几种情况: - -- `p`、`q` 在 `lca_node` 的子树中,且分别在 `lca_node` 的两侧子树中。 -- `p == lca_node`,且 `q` 在 `lca_node` 的左子树或右子树中。 -- `q == lca_node`,且 `p` 在 `lca_node` 的左子树或右子树中。 - -下面递归求解 `lca_node`。递归需要满足以下条件: - -- 如果 `p`、`q` 都不为空,则返回 `p`、`q` 的公共祖先。 -- 如果 `p`、`q` 只有一个存在,则返回存在的一个。 -- 如果 `p`、`q` 都不存在,则返回存在的一个。 - -具体思路为: - -- 如果当前节点 `node` 为 `None`,则说明 `p`、`q` 不在 `node` 的子树中,不可能为公共祖先,直接返回 `None`。 -- 如果当前节点 `node` 等于 `p` 或者 `q`,那么 `node` 就是 `p`、`q` 的最近公共祖先,直接返回 `node`。 -- 递归遍历左子树、右子树,并判断左右子树结果。 - - 如果左子树为空,则返回右子树。 - - 如果右子树为空,则返回左子树。 - - 如果左右子树都不为空,则说明 `p`、`q` 在当前根节点的两侧,当前根节点就是他们的最近公共祖先。 - - 如果左右子树都为空,则返回空。 - -## 代码 - -```python -class Solution: - def lowestCommonAncestor(self, root: TreeNode, p: TreeNode, q: TreeNode) -> TreeNode: - if root == p or root == q: - return root - - if root: - node_left = self.lowestCommonAncestor(root.left, p, q) - node_right = self.lowestCommonAncestor(root.right, p, q) - if node_left and node_right: - return root - elif not node_left: - return node_right - else: - return node_left - return None -``` - diff --git a/docs/solutions/Interviews/group-anagrams-lcci.md b/docs/solutions/Interviews/group-anagrams-lcci.md deleted file mode 100644 index ccde9231..00000000 --- a/docs/solutions/Interviews/group-anagrams-lcci.md +++ /dev/null @@ -1,42 +0,0 @@ -# [面试题 10.02. 变位词组](https://leetcode.cn/problems/group-anagrams-lcci/) - -- 标签:数组、哈希表、字符串、排序 -- 难度:中等 - -## 题目链接 - -- [面试题 10.02. 变位词组 - 力扣](https://leetcode.cn/problems/group-anagrams-lcci/) - -## 题目大意 - -给定一个字符串数组 `strs`。 - -要求:将所有变位词组合在一起。不需要考虑输出顺序。 - -- 变位词:字母相同,但排列不同的字符串。 - -## 解题思路 - -使用哈希表记录变位词。对每一个字符串进行排序,按照 `排序字符串:变位词数组` 的键值顺序进行存储。 - -最终将哈希表的值转换为对应数组返回结果。 - -## 代码 - -```python -class Solution: - def groupAnagrams(self, strs: List[str]) -> List[List[str]]: - str_dict = dict() - res = [] - for s in strs: - sort_s = str(sorted(s)) - if sort_s in str_dict: - str_dict[sort_s] += [s] - else: - str_dict[sort_s] = [s] - - for sort_s in str_dict: - res += [str_dict[sort_s]] - return res -``` - diff --git a/docs/solutions/Interviews/implement-queue-using-stacks-lcci.md b/docs/solutions/Interviews/implement-queue-using-stacks-lcci.md deleted file mode 100644 index 64993a2f..00000000 --- a/docs/solutions/Interviews/implement-queue-using-stacks-lcci.md +++ /dev/null @@ -1,74 +0,0 @@ -# [面试题 03.04. 化栈为队](https://leetcode.cn/problems/implement-queue-using-stacks-lcci/) - -- 标签:栈、设计、队列 -- 难度:简单 - -## 题目链接 - -- [面试题 03.04. 化栈为队 - 力扣](https://leetcode.cn/problems/implement-queue-using-stacks-lcci/) - -## 题目大意 - -要求:实现一个 MyQueue 类,要求仅使用两个栈实现先入先出队列。 - -## 解题思路 - -使用两个栈,`inStack` 用于输入,`outStack` 用于输出。 - -- `push` 操作:将元素压入 `inStack` 中。 -- `pop` 操作:如果 `outStack` 输出栈为空,将 `inStack` 输入栈元素依次取出,按顺序压入 `outStack` 栈。这样 `outStack` 栈的元素顺序和之前 `inStack` 元素顺序相反,`outStack` 顶层元素就是要取出的队头元素,将其移出,并返回该元素。如果 `outStack` 输出栈不为空,则直接取出顶层元素。 -- `peek` 操作:和 `pop` 操作类似,只不过最后一步不需要取出顶层元素,直接将其返回即可。 -- `empty` 操作:如果 `inStack` 和 `outStack` 都为空,则队列为空,否则队列不为空。 - -## 代码 - -```python -class MyQueue: - - def __init__(self): - """ - Initialize your data structure here. - """ - self.inStack = [] - self.outStack = [] - - - def push(self, x: int) -> None: - """ - Push element x to the back of queue. - """ - self.inStack.append(x) - - - def pop(self) -> int: - """ - Removes the element from in front of queue and returns that element. - """ - if (len(self.outStack) == 0): - while (len(self.inStack) != 0): - self.outStack.append(self.inStack[-1]) - self.inStack.pop() - top = self.outStack[-1] - self.outStack.pop() - return top - - - def peek(self) -> int: - """ - Get the front element. - """ - if (len(self.outStack) == 0): - while (len(self.inStack) != 0): - self.outStack.append(self.inStack[-1]) - self.inStack.pop() - top = self.outStack[-1] - return top - - - def empty(self) -> bool: - """ - Returns whether the queue is empty. - """ - return len(self.outStack) == 0 and len(self.inStack) == 0 -``` - diff --git a/docs/solutions/Interviews/index.md b/docs/solutions/Interviews/index.md deleted file mode 100644 index 9075fd7f..00000000 --- a/docs/solutions/Interviews/index.md +++ /dev/null @@ -1,32 +0,0 @@ -## 本章内容 - -- [面试题 01.07. 旋转矩阵](https://github.com/ITCharge/AlgoNote/tree/main/docs/solutions/Interviews/rotate-matrix-lcci.md) -- [面试题 01.08. 零矩阵](https://github.com/ITCharge/AlgoNote/tree/main/docs/solutions/Interviews/zero-matrix-lcci.md) -- [面试题 02.02. 返回倒数第 k 个节点](https://github.com/ITCharge/AlgoNote/tree/main/docs/solutions/Interviews/kth-node-from-end-of-list-lcci.md) -- [面试题 02.05. 链表求和](https://github.com/ITCharge/AlgoNote/tree/main/docs/solutions/Interviews/sum-lists-lcci.md) -- [面试题 02.06. 回文链表](https://github.com/ITCharge/AlgoNote/tree/main/docs/solutions/Interviews/palindrome-linked-list-lcci.md) -- [面试题 02.07. 链表相交](https://github.com/ITCharge/AlgoNote/tree/main/docs/solutions/Interviews/intersection-of-two-linked-lists-lcci.md) -- [面试题 02.08. 环路检测](https://github.com/ITCharge/AlgoNote/tree/main/docs/solutions/Interviews/linked-list-cycle-lcci.md) -- [面试题 03.02. 栈的最小值](https://github.com/ITCharge/AlgoNote/tree/main/docs/solutions/Interviews/min-stack-lcci.md) -- [面试题 03.04. 化栈为队](https://github.com/ITCharge/AlgoNote/tree/main/docs/solutions/Interviews/implement-queue-using-stacks-lcci.md) -- [面试题 04.02. 最小高度树](https://github.com/ITCharge/AlgoNote/tree/main/docs/solutions/Interviews/minimum-height-tree-lcci.md) -- [面试题 04.05. 合法二叉搜索树](https://github.com/ITCharge/AlgoNote/tree/main/docs/solutions/Interviews/legal-binary-search-tree-lcci.md) -- [面试题 04.06. 后继者](https://github.com/ITCharge/AlgoNote/tree/main/docs/solutions/Interviews/successor-lcci.md) -- [面试题 04.08. 首个共同祖先](https://github.com/ITCharge/AlgoNote/tree/main/docs/solutions/Interviews/first-common-ancestor-lcci.md) -- [面试题 04.12. 求和路径](https://github.com/ITCharge/AlgoNote/tree/main/docs/solutions/Interviews/paths-with-sum-lcci.md) -- [面试题 08.04. 幂集](https://github.com/ITCharge/AlgoNote/tree/main/docs/solutions/Interviews/power-set-lcci.md) -- [面试题 08.07. 无重复字符串的排列组合](https://github.com/ITCharge/AlgoNote/tree/main/docs/solutions/Interviews/permutation-i-lcci.md) -- [面试题 08.08. 有重复字符串的排列组合](https://github.com/ITCharge/AlgoNote/tree/main/docs/solutions/Interviews/permutation-ii-lcci.md) -- [面试题 08.09. 括号](https://github.com/ITCharge/AlgoNote/tree/main/docs/solutions/Interviews/bracket-lcci.md) -- [面试题 08.10. 颜色填充](https://github.com/ITCharge/AlgoNote/tree/main/docs/solutions/Interviews/color-fill-lcci.md) -- [面试题 08.12. 八皇后](https://github.com/ITCharge/AlgoNote/tree/main/docs/solutions/Interviews/eight-queens-lcci.md) -- [面试题 10.01. 合并排序的数组](https://github.com/ITCharge/AlgoNote/tree/main/docs/solutions/Interviews/sorted-merge-lcci.md) -- [面试题 10.02. 变位词组](https://github.com/ITCharge/AlgoNote/tree/main/docs/solutions/Interviews/group-anagrams-lcci.md) -- [面试题 10.09. 排序矩阵查找](https://github.com/ITCharge/AlgoNote/tree/main/docs/solutions/Interviews/sorted-matrix-search-lcci.md) -- [面试题 16.02. 单词频率](https://github.com/ITCharge/AlgoNote/tree/main/docs/solutions/Interviews/words-frequency-lcci.md) -- [面试题 16.05. 阶乘尾数](https://github.com/ITCharge/AlgoNote/tree/main/docs/solutions/Interviews/factorial-zeros-lcci.md) -- [面试题 16.26. 计算器](https://github.com/ITCharge/AlgoNote/tree/main/docs/solutions/Interviews/calculator-lcci.md) -- [面试题 17.06. 2出现的次数](https://github.com/ITCharge/AlgoNote/tree/main/docs/solutions/Interviews/number-of-2s-in-range-lcci.md) -- [面试题 17.14. 最小K个数](https://github.com/ITCharge/AlgoNote/tree/main/docs/solutions/Interviews/smallest-k-lcci.md) -- [面试题 17.15. 最长单词](https://github.com/ITCharge/AlgoNote/tree/main/docs/solutions/Interviews/longest-word-lcci.md) -- [面试题 17.17. 多次搜索](https://github.com/ITCharge/AlgoNote/tree/main/docs/solutions/Interviews/multi-search-lcci.md) diff --git a/docs/solutions/Interviews/intersection-of-two-linked-lists-lcci.md b/docs/solutions/Interviews/intersection-of-two-linked-lists-lcci.md deleted file mode 100644 index a985f070..00000000 --- a/docs/solutions/Interviews/intersection-of-two-linked-lists-lcci.md +++ /dev/null @@ -1,54 +0,0 @@ -# [面试题 02.07. 链表相交](https://leetcode.cn/problems/intersection-of-two-linked-lists-lcci/) - -- 标签:哈希表、链表、双指针 -- 难度:简单 - -## 题目链接 - -- [面试题 02.07. 链表相交 - 力扣](https://leetcode.cn/problems/intersection-of-two-linked-lists-lcci/) - -## 题目大意 - -给定两个链表的头节点 `headA`、`headB`。 - -要求:找出并返回两个单链表相交的起始节点。如果两个链表没有交点,返回 `None` 。 - -比如:链表 A 为 `[4, 1, 8, 4, 5]`,链表 B 为 `[5, 0, 1, 8, 4, 5]`。则如下图所示,两个链表相交的起始节点为 `8`,则输出结果为 `8`。 - -![](https://assets.leetcode.com/uploads/2018/12/13/160_example_1.png) - - - - - -## 解题思路 - -如果两个链表相交,那么从相交位置开始,到结束,必有一段等长且相同的节点。假设链表 `A` 的长度为 `m`、链表 `B` 的长度为 `n`,他们的相交序列有 `k` 个,则相交情况可以如下如所示: - -![](https://qcdn.itcharge.cn/images/20210401113538.png) - -现在问题是如何找到 `m - k` 或者 `n - k` 的位置。 - -考虑将链表 `A` 的末尾拼接上链表 `B`,链表 `B` 的末尾拼接上链表 `A`。 - -然后使用两个指针 `pA` 、`pB`,分别从链表 `A`、链表 `B` 的头节点开始遍历,如果走到共同的节点,则返回该节点。 - -否则走到两个链表末尾,返回 `None`。 - -![](https://qcdn.itcharge.cn/images/20210401114100.png) - -## 代码 - -```python -class Solution: - def getIntersectionNode(self, headA: ListNode, headB: ListNode) -> ListNode: - if headA == None or headB == None: - return None - pA = headA - pB = headB - while pA != pB : - pA = pA.next if pA != None else headB - pB = pB.next if pB != None else headA - return pA -``` - diff --git a/docs/solutions/Interviews/kth-node-from-end-of-list-lcci.md b/docs/solutions/Interviews/kth-node-from-end-of-list-lcci.md deleted file mode 100644 index adec3b65..00000000 --- a/docs/solutions/Interviews/kth-node-from-end-of-list-lcci.md +++ /dev/null @@ -1,38 +0,0 @@ -# [面试题 02.02. 返回倒数第 k 个节点](https://leetcode.cn/problems/kth-node-from-end-of-list-lcci/) - -- 标签:链表、双指针 -- 难度:简单 - -## 题目链接 - -- [面试题 02.02. 返回倒数第 k 个节点 - 力扣](https://leetcode.cn/problems/kth-node-from-end-of-list-lcci/) - -## 题目大意 - -给定一个链表的头节点 `head`,以及一个整数 `k`。 - -要求:返回链表的倒数第 `k` 个节点的值。 - -## 解题思路 - -常规思路是遍历一遍链表,求出链表长度,再遍历一遍到对应位置,返回该位置上的节点。 - -如果用一次遍历实现的话,可以使用快慢指针。让快指针先走 `k` 步,然后快慢指针、慢指针再同时走,每次一步,这样等快指针遍历到链表尾部的时候,慢指针就刚好遍历到了倒数第 `k` 个节点位置。返回该该位置上的节点即可。 - -## 代码 - -```python -class Solution: - def kthToLast(self, head: ListNode, k: int) -> int: - slow = head - fast = head - for _ in range(k): - if fast == None: - return fast - fast = fast.next - while fast: - slow = slow.next - fast = fast.next - return slow.val -``` - diff --git a/docs/solutions/Interviews/legal-binary-search-tree-lcci.md b/docs/solutions/Interviews/legal-binary-search-tree-lcci.md deleted file mode 100644 index d78f5baf..00000000 --- a/docs/solutions/Interviews/legal-binary-search-tree-lcci.md +++ /dev/null @@ -1,46 +0,0 @@ -# [面试题 04.05. 合法二叉搜索树](https://leetcode.cn/problems/legal-binary-search-tree-lcci/) - -- 标签:树、深度优先搜索、二叉搜索树、二叉树 -- 难度:中等 - -## 题目链接 - -- [面试题 04.05. 合法二叉搜索树 - 力扣](https://leetcode.cn/problems/legal-binary-search-tree-lcci/) - -## 题目大意 - -给定一个二叉树的根节点 `root`。 - -要求:检查该二叉树是否为二叉搜索树。 - -二叉搜索树特征: - -- 节点的左子树只包含小于当前节点的数。 -- 节点的右子树只包含大于当前节点的数。 -- 所有左子树和右子树自身必须也是二叉搜索树。 - -## 解题思路 - -根据题意进行递归遍历即可。前序、中序、后序遍历都可以。 - -以前序遍历为例,递归函数为:`preorderTraversal(root, min_v, max_v)` - -前序遍历时,先判断根节点的值是否在 `(min_v, max_v)` 之间。如果不在则直接返回 `False`。在区间内,则继续递归检测左右子树是否满足,都满足才是一棵二叉搜索树。 - -递归遍历左子树的时候,要将上界 `max_v` 改为左子树的根节点值,因为左子树上所有节点的值均小于根节点的值。同理,遍历右子树的时候,要将下界 `min_v` 改为右子树的根节点值,因为右子树上所有节点的值均大于根节点。 - -## 代码 - -```python -class Solution: - def isValidBST(self, root: TreeNode) -> bool: - def preorderTraversal(root, min_v, max_v): - if root == None: - return True - if root.val >= max_v or root.val <= min_v: - return False - return preorderTraversal(root.left, min_v, root.val) and preorderTraversal(root.right, root.val, max_v) - - return preorderTraversal(root, float('-inf'), float('inf')) -``` - diff --git a/docs/solutions/Interviews/linked-list-cycle-lcci.md b/docs/solutions/Interviews/linked-list-cycle-lcci.md deleted file mode 100644 index bc98e81f..00000000 --- a/docs/solutions/Interviews/linked-list-cycle-lcci.md +++ /dev/null @@ -1,47 +0,0 @@ -# [面试题 02.08. 环路检测](https://leetcode.cn/problems/linked-list-cycle-lcci/) - -- 标签:哈希表、链表、双指针 -- 难度:中等 - -## 题目链接 - -- [面试题 02.08. 环路检测 - 力扣](https://leetcode.cn/problems/linked-list-cycle-lcci/) - -## 题目大意 - -给定一个链表的头节点 `head`。 - -要求:判断链表中是否有环,如果有环则返回入环的第一个节点,无环则返回 None。 - -## 解题思路 - -利用两个指针,一个慢指针每次前进一步,快指针每次前进两步(两步或多步效果是等价的)。如果两个指针在链表头节点以外的某一节点相遇(即相等)了,那么说明链表有环,否则,如果(快指针)到达了某个没有后继指针的节点时,那么说明没环。 - -如果有环,则再定义一个指针,和慢指针一起每次移动一步,两个指针相遇的位置即为入口节点。 - -这是因为:假设入环位置为 A,快慢指针在在 B 点相遇,则相遇时慢指针走了 $a + b$ 步,快指针走了 $a + n(b+c) + b$ 步。 - -$2(a + b) = a + n(b + c) + b$。可以推出:$a = c + (n-1)(b + c)$。 - -我们可以发现:从相遇点到入环点的距离 $c$ 加上 $n-1$ 圈的环长 $b + c$ 刚好等于从链表头部到入环点的距离。 - -## 代码 - -```python -class Solution: - def detectCycle(self, head: ListNode) -> ListNode: - fast, slow = head, head - while True: - if not fast or not fast.next: - return None - fast = fast.next.next - slow = slow.next - if fast == slow: - break - - ans = head - while ans != slow: - ans, slow = ans.next, slow.next - return ans -``` - diff --git a/docs/solutions/Interviews/longest-word-lcci.md b/docs/solutions/Interviews/longest-word-lcci.md deleted file mode 100644 index 015aab7e..00000000 --- a/docs/solutions/Interviews/longest-word-lcci.md +++ /dev/null @@ -1,95 +0,0 @@ -# [面试题 17.15. 最长单词](https://leetcode.cn/problems/longest-word-lcci/) - -- 标签:字典树、数组、哈希表、字符串 -- 难度:中等 - -## 题目链接 - -- [面试题 17.15. 最长单词 - 力扣](https://leetcode.cn/problems/longest-word-lcci/) - -## 题目大意 - -给定一组单词 `words`。 - -要求:找出其中的最长单词,且该单词由这组单词中的其他单词组合而成。若有多个长度相同的结果,返回其中字典序最小的一项,若没有符合要求的单词则返回空字符串。 - -## 解题思路 - -先将所有单词按照长度从长到短排序,相同长度的字典序小的排在前面。然后将所有单词存入字典树中。 - -然后一重循环遍历所有单词 `word`,二重循环遍历单词中所有字符 `word[i]`。 - -如果当前遍历的字符为单词末尾,递归判断从 `i + 1` 位置开始,剩余部分是否可以切分为其他单词组合,如果可以切分,则返回当前单词 `word`。如果不可以切分,则返回空字符串 `""`。 - -## 代码 - -```python -class Trie: - - def __init__(self): - """ - Initialize your data structure here. - """ - self.children = dict() - self.isEnd = False - - - def insert(self, word: str) -> None: - """ - Inserts a word into the trie. - """ - cur = self - for ch in word: - if ch not in cur.children: - cur.children[ch] = Trie() - cur = cur.children[ch] - cur.isEnd = True - - - def search(self, word: str) -> bool: - """ - Returns if the word is in the trie. - """ - cur = self - for ch in word: - if ch not in cur.children: - return False - cur = cur.children[ch] - - return cur is not None and cur.isEnd - - def splitToWord(self, remain): - if not remain or remain == "": - return True - cur = self - for i in range(len(remain)): - ch = remain[i] - if ch not in cur.children: - return False - if cur.children[ch].isEnd and self.splitToWord(remain[i + 1:]): - return True - cur = cur.children[ch] - return False - - def dfs(self, words): - for word in words: - cur = self - size = len(word) - for i in range(size): - ch = word[i] - if i < size - 1 and cur.children[ch].isEnd and self.splitToWord(word[i+1:]): - return word - cur = cur.children[ch] - return "" - -class Solution: - def longestWord(self, words: List[str]) -> str: - words.sort(key=lambda x: (-len(x), x)) - trie_tree = Trie() - for word in words: - trie_tree.insert(word) - - ans = trie_tree.dfs(words) - return ans -``` - diff --git a/docs/solutions/Interviews/min-stack-lcci.md b/docs/solutions/Interviews/min-stack-lcci.md deleted file mode 100644 index 44a538ff..00000000 --- a/docs/solutions/Interviews/min-stack-lcci.md +++ /dev/null @@ -1,59 +0,0 @@ -# [面试题 03.02. 栈的最小值](https://leetcode.cn/problems/min-stack-lcci/) - -- 标签:栈、设计 -- 难度:简单 - -## 题目链接 - -- [面试题 03.02. 栈的最小值 - 力扣](https://leetcode.cn/problems/min-stack-lcci/) - -## 题目大意 - -设计一个「栈」,要求实现 `push` ,`pop` ,`top` ,`getMin` 操作,其中 `getMin` 要求能在常数时间内实现。 - -## 解题思路 - -使用一个栈,栈元素中除了保存当前值之外,再保存一个当前最小值。 - -- `push` 操作:如果栈不为空,则判断当前值与栈顶元素所保存的最小值,并更新当前最小值,将新元素保存到栈中。 -- `pop`操作:正常出栈 -- `top` 操作:返回栈顶元素保存的值。 -- `getMin` 操作:返回栈顶元素保存的最小值。 - -## 代码 - -```python -class MinStack: - - def __init__(self): - """ - initialize your data structure here. - """ - self.stack = [] - - class Node: - def __init__(self, x): - self.val = x - self.min = x - - def push(self, x: int) -> None: - node = self.Node(x) - if len(self.stack) == 0: - self.stack.append(node) - else: - topNode = self.stack[-1] - if node.min > topNode.min: - node.min = topNode.min - - self.stack.append(node) - - def pop(self) -> None: - self.stack.pop() - - def top(self) -> int: - return self.stack[-1].val - - def getMin(self) -> int: - return self.stack[-1].min -``` - diff --git a/docs/solutions/Interviews/minimum-height-tree-lcci.md b/docs/solutions/Interviews/minimum-height-tree-lcci.md deleted file mode 100644 index 7b22bf8f..00000000 --- a/docs/solutions/Interviews/minimum-height-tree-lcci.md +++ /dev/null @@ -1,34 +0,0 @@ -# [面试题 04.02. 最小高度树](https://leetcode.cn/problems/minimum-height-tree-lcci/) - -- 标签:树、二叉搜索树、数组、分治、二叉树 -- 难度:简单 - -## 题目链接 - -- [面试题 04.02. 最小高度树 - 力扣](https://leetcode.cn/problems/minimum-height-tree-lcci/) - -## 题目大意 - -给定一个升序的有序数组 `nums`。 - -要求:创建一棵高度最小的二叉搜索树(高度平衡的二叉搜索树)。 - -## 解题思路 - -直观上,如果把数组的中间元素当做根,那么数组左侧元素都小于根节点,右侧元素都大于根节点,且左右两侧元素个数相同,或最多相差 `1` 个。那么构建的树高度差也不会超过 `1`。所以猜想出:如果左右子树约平均,树就越平衡。这样我们就可以每次取中间元素作为当前的根节点,两侧的元素作为左右子树递归建树,左侧区间 `[L, mid - 1]` 作为左子树,右侧区间 `[mid + 1, R]` 作为右子树。 - -## 代码 - -```python -class Solution: - def sortedArrayToBST(self, nums: List[int]) -> TreeNode: - size = len(nums) - if size == 0: - return None - mid = size // 2 - root = TreeNode(nums[mid]) - root.left = Solution.sortedArrayToBST(self, nums[:mid]) - root.right = Solution.sortedArrayToBST(self, nums[mid + 1:]) - return root -``` - diff --git a/docs/solutions/Interviews/multi-search-lcci.md b/docs/solutions/Interviews/multi-search-lcci.md deleted file mode 100644 index 12891e29..00000000 --- a/docs/solutions/Interviews/multi-search-lcci.md +++ /dev/null @@ -1,80 +0,0 @@ -# [面试题 17.17. 多次搜索](https://leetcode.cn/problems/multi-search-lcci/) - -- 标签:字典树、数组、哈希表、字符串、字符串匹配、滑动窗口 -- 难度:中等 - -## 题目链接 - -- [面试题 17.17. 多次搜索 - 力扣](https://leetcode.cn/problems/multi-search-lcci/) - -## 题目大意 - -给定一个较长字符串 `big` 和一个包含较短字符串的数组 `smalls`。 - -要求:设计一个方法,根据 `smalls` 中的每一个较短字符串,对 `big` 进行搜索。输出 `smalls` 中的字符串在 `big` 里出现的所有位置 `positions`,其中 `positions[i]` 为 `smalls[i]` 出现的所有位置。 - -## 解题思路 - -构建字典树,将 `smalls` 中所有字符串存入字典树中,并在字典树中记录下插入字符串的顺序下标。 - -然后一重循环遍历 `big`,表示从第 `i` 位置开始的字符串 `big[i:]`。然后在字符串前缀中搜索对应的单词,将所有符合要求的单词插入顺序位置存入列表中,返回列表。 - -对于列表中每个单词插入下标顺序 `index` 和 `big[i:]` 来说, `i` 就是 `smalls` 中第 `index` 个字符串所对应在 `big` 中的开始位置,将其存入答案数组并返回即可。 - -## 代码 - -```python -class Trie: - - def __init__(self): - """ - Initialize your data structure here. - """ - self.children = dict() - self.isEnd = False - self.index = -1 - - - def insert(self, word: str, index: int) -> None: - """ - Inserts a word into the trie. - """ - cur = self - for ch in word: - if ch not in cur.children: - cur.children[ch] = Trie() - cur = cur.children[ch] - cur.isEnd = True - cur.index = index - - - def search(self, text: str) -> list: - """ - Returns if the word is in the trie. - """ - cur = self - res = [] - for i in range(len(text)): - ch = text[i] - if ch not in cur.children: - return res - cur = cur.children[ch] - if cur.isEnd: - res.append(cur.index) - return res - -class Solution: - def multiSearch(self, big: str, smalls: List[str]) -> List[List[int]]: - trie_tree = Trie() - for i in range(len(smalls)): - word = smalls[i] - trie_tree.insert(word, i) - - res = [[] for _ in range(len(smalls))] - - for i in range(len(big)): - for index in trie_tree.search(big[i:]): - res[index].append(i) - return res -``` - diff --git a/docs/solutions/Interviews/number-of-2s-in-range-lcci.md b/docs/solutions/Interviews/number-of-2s-in-range-lcci.md deleted file mode 100644 index 3fe09ff1..00000000 --- a/docs/solutions/Interviews/number-of-2s-in-range-lcci.md +++ /dev/null @@ -1,85 +0,0 @@ -# [面试题 17.06. 2出现的次数](https://leetcode.cn/problems/number-of-2s-in-range-lcci/) - -- 标签:递归、数学、动态规划 -- 难度:困难 - -## 题目链接 - -- [面试题 17.06. 2出现的次数 - 力扣](https://leetcode.cn/problems/number-of-2s-in-range-lcci/) - -## 题目大意 - -**描述**:给定一个整数 $n$。 - -**要求**:计算从 $0$ 到 $n$ (包含 $n$) 中数字 $2$ 出现的次数。 - -**说明**: - -- $n \le 10^9$。 - -**示例**: - -- 示例 1: - -```python -输入: 25 -输出: 9 -解释: (2, 12, 20, 21, 22, 23, 24, 25)(注意 22 应该算作两次) -``` - -## 解题思路 - -### 思路 1:动态规划 + 数位 DP - -将 $n$ 转换为字符串 $s$,定义递归函数 `def dfs(pos, cnt, isLimit):` 表示构造第 $pos$ 位及之后所有数位中数字 $2$ 出现的个数。接下来按照如下步骤进行递归。 - -1. 从 `dfs(0, 0, True)` 开始递归。 `dfs(0, 0, True)` 表示: - 1. 从位置 $0$ 开始构造。 - 2. 初始数字 $2$ 出现的个数为 $0$。 - 3. 开始时受到数字 $n$ 对应最高位数位的约束。 -2. 如果遇到 $pos == len(s)$,表示到达数位末尾,此时:返回数字 $2$ 出现的个数 $cnt$。 -3. 如果 $pos \ne len(s)$,则定义方案数 $ans$,令其等于 $0$,即:`ans = 0`。 -4. 如果遇到 $isNum == False$,说明之前位数没有填写数字,当前位可以跳过,这种情况下方案数等于 $pos + 1$ 位置上没有受到 $pos$ 位的约束,并且之前没有填写数字时的方案数,即:`ans = dfs(i + 1, state, False, False)`。 -5. 如果 $isNum == True$,则当前位必须填写一个数字。此时: - 1. 因为不需要考虑前导 $0$ 所以当前位数位所能选择的最小数字($minX$)为 $0$。 - 2. 根据 $isLimit$ 来决定填当前位数位所能选择的最大数字($maxX$)。 - 3. 然后根据 $[minX, maxX]$ 来枚举能够填入的数字 $d$。 - 4. 方案数累加上当前位选择 $d$ 之后的方案数,即:`ans += dfs(pos + 1, cnt + (d == 2), isLimit and d == maxX)`。 - 1. `cnt + (d == 2)` 表示之前数字 $2$ 出现的个数加上当前位为数字 $2$ 的个数。 - 2. `isLimit and d == maxX` 表示 $pos + 1$ 位受到之前位 $pos$ 位限制。 -6. 最后的方案数为 `dfs(0, 0, True)`,将其返回即可。 - -### 思路 1:代码 - -```python -class Solution: - def numberOf2sInRange(self, n: int) -> int: - # 将 n 转换为字符串 s - s = str(n) - - @cache - # pos: 第 pos 个数位 - # cnt: 之前数字 2 出现的个数。 - # isLimit: 表示是否受到选择限制。如果为真,则第 pos 位填入数字最多为 s[pos];如果为假,则最大可为 9。 - def dfs(pos, cnt, isLimit): - if pos == len(s): - return cnt - - ans = 0 - # 不需要考虑前导 0,则最小可选择数字为 0 - minX = 0 - # 如果受到选择限制,则最大可选择数字为 s[pos],否则最大可选择数字为 9。 - maxX = int(s[pos]) if isLimit else 9 - - # 枚举可选择的数字 - for d in range(minX, maxX + 1): - ans += dfs(pos + 1, cnt + (d == 2), isLimit and d == maxX) - return ans - - return dfs(0, 0, True) -``` - -### 思路 1:复杂度分析 - -- **时间复杂度**:$O(\log n)$。 -- **空间复杂度**:$O(\log n)$。 diff --git a/docs/solutions/Interviews/palindrome-linked-list-lcci.md b/docs/solutions/Interviews/palindrome-linked-list-lcci.md deleted file mode 100644 index 9907bb09..00000000 --- a/docs/solutions/Interviews/palindrome-linked-list-lcci.md +++ /dev/null @@ -1,32 +0,0 @@ -# [面试题 02.06. 回文链表](https://leetcode.cn/problems/palindrome-linked-list-lcci/) - -- 标签:栈、递归、链表、双指针 -- 难度:简单 - -## 题目链接 - -- [面试题 02.06. 回文链表 - 力扣](https://leetcode.cn/problems/palindrome-linked-list-lcci/) - -## 题目大意 - -给定一个链表的头节点 `head`。 - -要求:判断该链表是否为回文链表。 - -## 解题思路 - -利用数组,将链表元素依次存入。然后再使用两个指针,一个指向数组开始位置,一个指向数组结束位置,依次判断首尾对应元素是否相等,若都相等,则为回文链表。若不相等,则不是回文链表。 - -## 代码 - -```python -class Solution: - def isPalindrome(self, head: ListNode) -> bool: - nodes = [] - p1 = head - while p1 != None: - nodes.append(p1.val) - p1 = p1.next - return nodes == nodes[::-1] -``` - diff --git a/docs/solutions/Interviews/paths-with-sum-lcci.md b/docs/solutions/Interviews/paths-with-sum-lcci.md deleted file mode 100644 index 0cec25c8..00000000 --- a/docs/solutions/Interviews/paths-with-sum-lcci.md +++ /dev/null @@ -1,45 +0,0 @@ -# [面试题 04.12. 求和路径](https://leetcode.cn/problems/paths-with-sum-lcci/) - -- 标签:树、深度优先搜索、二叉树 -- 难度:中等 - -## 题目链接 - -- [面试题 04.12. 求和路径 - 力扣](https://leetcode.cn/problems/paths-with-sum-lcci/) - -## 题目大意 - -给定一个二叉树的根节点 `root`,和一个整数 `targetSum`。 - -要求:求出该二叉树里节点值之和等于 `targetSum` 的路径的数目。 - -- 路径:不需要从根节点开始,也不需要在叶子节点结束,但是路径方向必须是向下的(只能从父节点到子节点)。 - -## 解题思路 - -直观想法是: - -以每一个节点 `node` 为起始节点,向下检测延伸的路径。递归遍历每一个节点所有可能的路径,然后将这些路径数目加起来即为答案。 - -但是这样会存在许多重复计算。我们可以定义节点的前缀和来减少重复计算。 - -- 节点的前缀和:从根节点到当前节点路径上所有节点的和。 - -有了节点的前缀和,我们就可以通过前缀和来计算两节点之间的路劲和。即:`则两节点之间的路径和 = 两节点之间的前缀和之差`。 - -为了计算符合要求的路径数量,我们用哈希表存储「前缀和的节点数量」。哈希表以「当前节点的前缀和」为键,以「该前缀和的节点数量」为值。这样就能通过哈希表直接计算出符合要求的路径数量,从而累加到答案上。 - -整个算法的具体步骤如下: - -- 通过先序遍历方式递归遍历二叉树,计算每一个节点的前缀和 `cur_sum`。 -- 从哈希表中取出 `cur_sum - target_sum` 的路径数量(也就是表示存在从前缀和为 `cur_sum - target_sum` 所对应的节点到前缀和为 `cur_sum` 所对应的节点的路径个数)累加到答案 `res` 中。 -- 然后以「当前节点的前缀和」为键,以「该前缀和的节点数量」为值,存入哈希表中。 -- 递归遍历二叉树,并累加答案值。 -- 恢复哈希表「当前前缀和的节点数量」,返回答案。 - -## 代码 - -```python - -``` - diff --git a/docs/solutions/Interviews/permutation-i-lcci.md b/docs/solutions/Interviews/permutation-i-lcci.md deleted file mode 100644 index f5cd4488..00000000 --- a/docs/solutions/Interviews/permutation-i-lcci.md +++ /dev/null @@ -1,46 +0,0 @@ -# [面试题 08.07. 无重复字符串的排列组合](https://leetcode.cn/problems/permutation-i-lcci/) - -- 标签:字符串、回溯 -- 难度:中等 - -## 题目链接 - -- [面试题 08.07. 无重复字符串的排列组合 - 力扣](https://leetcode.cn/problems/permutation-i-lcci/) - -## 题目大意 - -给定一个字符串 `S`。 - -要求:打印出该字符串中字符的所有排列。可以以任意顺序返回这个字符串数组,但里边不能有重复元素。 - -## 解题思路 - -使用 `visited` 数组标记该元素在当前排列中是否被访问过。若未被访问过则将其加入排列中,并在访问后将该元素变为未访问状态。然后进行回溯遍历。 - -## 代码 - -```python -class Solution: - res = [] - path = [] - - def backtrack(self, S, visited): - if len(self.path) == len(S): - self.res.append(''.join(self.path)) - return - for i in range(len(S)): - if not visited[i]: - visited[i] = True - self.path.append(S[i]) - self.backtrack(S, visited) - self.path.pop() - visited[i] = False - - def permutation(self, S: str) -> List[str]: - self.res.clear() - self.path.clear() - visited = [False for _ in range(len(S))] - self.backtrack(S, visited) - return self.res -``` - diff --git a/docs/solutions/Interviews/permutation-ii-lcci.md b/docs/solutions/Interviews/permutation-ii-lcci.md deleted file mode 100644 index 8f9edeb5..00000000 --- a/docs/solutions/Interviews/permutation-ii-lcci.md +++ /dev/null @@ -1,55 +0,0 @@ -# [面试题 08.08. 有重复字符串的排列组合](https://leetcode.cn/problems/permutation-ii-lcci/) - -- 标签:字符串、回溯 -- 难度:中等 - -## 题目链接 - -- [面试题 08.08. 有重复字符串的排列组合 - 力扣](https://leetcode.cn/problems/permutation-ii-lcci/) - -## 题目大意 - -给定一个字符串 `s`,字符串中包含有重复字符。 - -要求:打印出该字符串中字符的所有排列。可以以任意顺序返回这个字符串数组。 - -## 解题思路 - -因为原字符串可能含有重复元素,所以在回溯的时候需要进行去重。先将字符串 `s` 转为 `list` 列表,再对列表进行排序,然后使用 `visited` 数组标记该元素在当前排列中是否被访问过。若未被访问过则将其加入排列中,并在访问后将该元素变为未访问状态。 - -然后再递归遍历下一层元素之前,增加一句语句进行判重:`if i > 0 and nums[i] == nums[i - 1] and not visited[i - 1]: continue`。 - -然后进行回溯遍历。 - -## 代码 - -```python -class Solution: - res = [] - path = [] - - def backtrack(self, ls, visited): - if len(self.path) == len(ls): - self.res.append(''.join(self.path)) - return - for i in range(len(ls)): - if i > 0 and ls[i] == ls[i - 1] and not visited[i - 1]: - continue - - if not visited[i]: - visited[i] = True - self.path.append(ls[i]) - self.backtrack(ls, visited) - self.path.pop() - visited[i] = False - - def permutation(self, S: str) -> List[str]: - self.res.clear() - self.path.clear() - ls = list(S) - ls.sort() - visited = [False for _ in range(len(S))] - self.backtrack(ls, visited) - return self.res -``` - diff --git a/docs/solutions/Interviews/power-set-lcci.md b/docs/solutions/Interviews/power-set-lcci.md deleted file mode 100644 index b6f4d166..00000000 --- a/docs/solutions/Interviews/power-set-lcci.md +++ /dev/null @@ -1,35 +0,0 @@ -# [面试题 08.04. 幂集](https://leetcode.cn/problems/power-set-lcci/) - -- 标签:位运算、数组、回溯 -- 难度:中等 - -## 题目链接 - -- [面试题 08.04. 幂集 - 力扣](https://leetcode.cn/problems/power-set-lcci/) - -## 题目大意 - -给定一个集合 `nums`,集合中不包含重复元素。 - -压枪欧秋:返回该集合的所有子集。 - -## 解题思路 - -回溯算法,遍历集合 `nums`。为了使得子集不重复,每次遍历从当前位置的下一个位置进行下一层遍历。 - -## 代码 - -```python -class Solution: - def subsets(self, nums: List[int]) -> List[List[int]]: - def backtrack(size, subset, index): - res.append(subset) - for i in range(index, size): - backtrack(size, subset + [nums[i]], i + 1) - - size = len(nums) - res = list() - backtrack(size, [], 0) - return res -``` - diff --git a/docs/solutions/Interviews/rotate-matrix-lcci.md b/docs/solutions/Interviews/rotate-matrix-lcci.md deleted file mode 100644 index 275cbe8f..00000000 --- a/docs/solutions/Interviews/rotate-matrix-lcci.md +++ /dev/null @@ -1,67 +0,0 @@ -# [面试题 01.07. 旋转矩阵](https://leetcode.cn/problems/rotate-matrix-lcci/) - -- 标签:数组、数学、矩阵 -- 难度:中等 - -## 题目链接 - -- [面试题 01.07. 旋转矩阵 - 力扣](https://leetcode.cn/problems/rotate-matrix-lcci/) - -## 题目大意 - -给定一个 `n * n` 大小的二维矩阵用来表示图像,其中每个像素的大小为 4 字节。 - -要求:设计一种算法,将图像旋转 90 度。并且要不占用额外内存空间。 - -## 解题思路 - -题目要求不占用额外内存空间,就是要在原二维矩阵上直接进行旋转操作。我们可以用翻转操作代替旋转操作。具体可以分为两步: - -1. 上下翻转。 - -2. 主对角线翻转。 - -举个例子: - -``` - 1 2 3 4 - 5 6 7 8 - 9 10 11 12 -13 14 15 16 -``` - -上下翻转后变为: - -``` -13 14 15 16 - 9 10 11 12 - 5 6 7 8 - 1 2 3 4 -``` - -在经过主对角线翻转后变为: - -``` -13 9 5 1 -14 10 6 2 -15 11 7 3 -16 12 8 4 -``` - -## 代码 - -```python -class Solution: - def rotate(self, matrix: List[List[int]]) -> None: - """ - Do not return anything, modify matrix in-place instead. - """ - size = len(matrix) - for i in range(size // 2): - for j in range(size): - matrix[i][j], matrix[size - i - 1][j] = matrix[size - i - 1][j], matrix[i][j] - for i in range(size): - for j in range(i): - matrix[i][j], matrix[j][i] = matrix[j][i], matrix[i][j] -``` - diff --git a/docs/solutions/Interviews/smallest-k-lcci.md b/docs/solutions/Interviews/smallest-k-lcci.md deleted file mode 100644 index cc05a832..00000000 --- a/docs/solutions/Interviews/smallest-k-lcci.md +++ /dev/null @@ -1,73 +0,0 @@ -# [面试题 17.14. 最小K个数](https://leetcode.cn/problems/smallest-k-lcci/) - -- 标签:数组、分治、快速选择、排序、堆(优先队列) -- 难度:中等 - -## 题目链接 - -- [面试题 17.14. 最小K个数 - 力扣](https://leetcode.cn/problems/smallest-k-lcci/) - -## 题目大意 - -给定整数数组 `arr`,再给定一个整数 `k`。 - -要求:返回数组 `arr` 中最小的 `k` 个数。 - -## 解题思路 - -直接可以想到的思路是:排序后输出数组上对应的最小的 k 个数。所以问题关键在于排序方法的复杂度。 - -冒泡排序、选择排序、插入排序时间复杂度 $O(n^2)$ 太高了,解答会超时。 - -可考虑堆排序、归并排序、快速排序。本题使用堆排序。具体做法如下: - -1. 利用数组前 `k` 个元素,建立大小为 `k` 的大顶堆。 -2. 遍历数组 `[k, size - 1]` 的元素,判断其与堆顶元素关系,如果比堆顶元素小,则将其赋值给堆顶元素,再对大顶堆进行调整。 -3. 最后输出前调整过后的大顶堆的前 `k` 个元素。 - -## 代码 - -```python -class Solution: - def heapify(self, nums: [int], index: int, end: int): - left = index * 2 + 1 - right = left + 1 - while left <= end: - # 当前节点为非叶子节点 - max_index = index - if nums[left] > nums[max_index]: - max_index = left - if right <= end and nums[right] > nums[max_index]: - max_index = right - if index == max_index: - # 如果不用交换,则说明已经交换结束 - break - nums[index], nums[max_index] = nums[max_index], nums[index] - # 继续调整子树 - index = max_index - left = index * 2 + 1 - right = left + 1 - - # 初始化大顶堆 - def buildMaxHeap(self, nums: [int], k: int): - # (k-2) // 2 是最后一个非叶节点,叶节点不用调整 - for i in range((k - 2) // 2, -1, -1): - self.heapify(nums, i, k - 1) - return nums - - def smallestK(self, arr: List[int], k: int) -> List[int]: - size = len(arr) - if k <= 0 or not arr: - return [] - if size <= k: - return arr - - self.buildMaxHeap(arr, k) - for i in range(k, size): - if arr[i] < arr[0]: - arr[i], arr[0] = arr[0], arr[i] - self.heapify(arr, 0, k - 1) - - return arr[:k] -``` - diff --git a/docs/solutions/Interviews/sorted-matrix-search-lcci.md b/docs/solutions/Interviews/sorted-matrix-search-lcci.md deleted file mode 100644 index 61c554e6..00000000 --- a/docs/solutions/Interviews/sorted-matrix-search-lcci.md +++ /dev/null @@ -1,90 +0,0 @@ -# [面试题 10.09. 排序矩阵查找](https://leetcode.cn/problems/sorted-matrix-search-lcci/) - -- 标签:数组、二分查找、分治、矩阵 -- 难度:中等 - -## 题目链接 - -- [面试题 10.09. 排序矩阵查找 - 力扣](https://leetcode.cn/problems/sorted-matrix-search-lcci/) - -## 题目大意 - -给定一个 `m * n` 大小的有序整数矩阵。每一行、每一列都按升序排列。再给定一个目标值 `target`。 - -要求:判断矩阵中是否可以找到 `target`,若找到 `target`,返回 `True`,否则返回 `False`。 - -## 解题思路 - -矩阵是有序的,可以考虑使用二分搜索来进行查找。 - -迭代对角线元素,假设对角线元素的坐标为 `(row, col)`。把数组元素按对角线分为右上角部分和左下角部分。 - -则对于当前对角线元素右侧第 `row` 行、对角线元素下侧第 `col` 列进行二分查找。 - -- 如果找到目标,直接返回 `True`。 -- 如果找不到目标,则缩小范围,继续查找。 -- 直到所有对角线元素都遍历完,依旧没找到,则返回 `False`。 - -## 代码 - -```python -class Solution: - def diagonalBinarySearch(self, matrix, diagonal, target): - left = 0 - right = diagonal - while left < right: - mid = left + (right - left) // 2 - if matrix[mid][mid] < target: - left = mid + 1 - else: - right = mid - return left - - def rowBinarySearch(self, matrix, begin, cols, target): - left = begin - right = cols - while left < right: - mid = left + (right - left) // 2 - if matrix[begin][mid] < target: - left = mid + 1 - elif matrix[begin][mid] > target: - right = mid - 1 - else: - left = mid - break - return begin <= left <= cols and matrix[begin][left] == target - - def colBinarySearch(self, matrix, begin, rows, target): - left = begin + 1 - right = rows - while left < right: - mid = left + (right - left) // 2 - if matrix[mid][begin] < target: - left = mid + 1 - elif matrix[mid][begin] > target: - right = mid - 1 - else: - left = mid - break - return begin <= left <= rows and matrix[left][begin] == target - - def searchMatrix(self, matrix: List[List[int]], target: int) -> bool: - rows = len(matrix) - if rows == 0: - return False - cols = len(matrix[0]) - if cols == 0: - return False - - min_val = min(rows, cols) - index = self.diagonalBinarySearch(matrix, min_val - 1, target) - if matrix[index][index] == target: - return True - for i in range(index + 1): - row_search = self.rowBinarySearch(matrix, i, cols - 1, target) - col_search = self.colBinarySearch(matrix, i, rows - 1, target) - if row_search or col_search: - return True - return False -``` - diff --git a/docs/solutions/Interviews/sorted-merge-lcci.md b/docs/solutions/Interviews/sorted-merge-lcci.md deleted file mode 100644 index ea05bd85..00000000 --- a/docs/solutions/Interviews/sorted-merge-lcci.md +++ /dev/null @@ -1,72 +0,0 @@ -# [面试题 10.01. 合并排序的数组](https://leetcode.cn/problems/sorted-merge-lcci/) - -- 标签:数组、双指针、排序 -- 难度:简单 - -## 题目链接 - -- [面试题 10.01. 合并排序的数组 - 力扣](https://leetcode.cn/problems/sorted-merge-lcci/) - -## 题目大意 - -**描述**:给定两个排序后的数组 `A` 和 `B`,以及 `A` 的元素数量 `m` 和 `B` 的元素数量 `n`。 `A` 的末端有足够的缓冲空间容纳 `B`。 - -**要求**:编写一个方法,将 `B` 合并入 `A` 并排序。 - -**说明**: - -- $A.length == n + m$。 - -**示例**: - -- 示例 1: - -```python -输入: -A = [1,2,3,0,0,0], m = 3 -B = [2,5,6], n = 3 - -输出: [1,2,2,3,5,6] -``` - -## 解题思路 - -### 思路 1:归并排序 - -可以利用归并排序算法的归并步骤思路。 - -1. 使用两个指针分别表示`A`、`B` 正在处理的元素下标。 -2. 对 `A`、`B` 进行归并操作,将结果存入新数组中。归并之后,再将所有元素赋值到数组 `A` 中。 - -### 思路 1:代码 - -```python -class Solution: - def merge(self, A: List[int], m: int, B: List[int], n: int) -> None: - """ - Do not return anything, modify A in-place instead. - """ - arr = [] - index_A, index_B = 0, 0 - while index_A < m and index_B < n: - if A[index_A] <= B[index_B]: - arr.append(A[index_A]) - index_A += 1 - else: - arr.append(B[index_B]) - index_B += 1 - while index_A < m: - arr.append(A[index_A]) - index_A += 1 - while index_B < n: - arr.append(B[index_B]) - index_B += 1 - for i in range(m + n): - A[i] = arr[i] -``` - -### 思路 1:复杂度分析 - -- **时间复杂度**:$O(m + n)$。 -- **空间复杂度**:$O(m + n)$。 - diff --git a/docs/solutions/Interviews/successor-lcci.md b/docs/solutions/Interviews/successor-lcci.md deleted file mode 100644 index 0576afea..00000000 --- a/docs/solutions/Interviews/successor-lcci.md +++ /dev/null @@ -1,39 +0,0 @@ -# [面试题 04.06. 后继者](https://leetcode.cn/problems/successor-lcci/) - -- 标签:树、深度优先搜索、二叉搜索树、二叉树 -- 难度:中等 - -## 题目链接 - -- [面试题 04.06. 后继者 - 力扣](https://leetcode.cn/problems/successor-lcci/) - -## 题目大意 - -给定一棵二叉搜索树的根节点 `root` 和其中一个节点 `p`。 - -要求:找出该节点在树中的中序后继,即按照中序遍历的顺序节点 `p` 的下一个节点。如果节点 `p` 没有对应的下一个节点,则返回 `None`。 - -## 解题思路 - -递归遍历,具体步骤如下: - -- 如果 `root.val` 小于等于 `p.val`,则直接从 `root` 的右子树递归查找比 `p.val` 大的节点,从而找到中序后继。 -- 如果 `root.val` 大于 `p.val`,则 `root` 有可能是中序后继,也有可能是 `root` 的左子树。则从 `root` 的左子树递归查找更接近(更小的)。如果查找的值为 `None`,则当前 `root` 就是中序后继,否则继续递归查找,从而找到中序后继。 - -## 代码 - -```python -class Solution: - def inorderSuccessor(self, root: TreeNode, p: TreeNode) -> TreeNode: - if not p or not root: - return None - - if root.val <= p.val: - node = self.inorderSuccessor(root.right, p) - else: - node = self.inorderSuccessor(root.left, p) - if not node: - node = root - return node -``` - diff --git a/docs/solutions/Interviews/sum-lists-lcci.md b/docs/solutions/Interviews/sum-lists-lcci.md deleted file mode 100644 index 7962b73d..00000000 --- a/docs/solutions/Interviews/sum-lists-lcci.md +++ /dev/null @@ -1,47 +0,0 @@ -# [面试题 02.05. 链表求和](https://leetcode.cn/problems/sum-lists-lcci/) - -- 标签:递归、链表、数学 -- 难度:中等 - -## 题目链接 - -- [面试题 02.05. 链表求和 - 力扣](https://leetcode.cn/problems/sum-lists-lcci/) - -## 题目大意 - -给定两个非空的链表 `l1` 和 `l2`,表示两个非负整数,每位数字都是按照逆序的方式存储的,每个节点存储一位数字。 - -要求:计算两个整数的和,并逆序返回表示和的链表。 - -## 解题思路 - -模拟大数加法,按位相加,将结果添加到新链表上。需要注意进位和对 `10` 取余。 - -## 代码 - -```python -class Solution: - def addTwoNumbers(self, l1: ListNode, l2: ListNode) -> ListNode: - head = curr = ListNode(0) - carry = 0 - while l1 or l2 or carry: - if l1: - num1 = l1.val - l1 = l1.next - else: - num1 = 0 - if l2: - num2 = l2.val - l2 = l2.next - else: - num2 = 0 - - sum = num1 + num2 + carry - carry = sum // 10 - - curr.next = ListNode(sum % 10) - curr = curr.next - - return head.next -``` - diff --git a/docs/solutions/Interviews/words-frequency-lcci.md b/docs/solutions/Interviews/words-frequency-lcci.md deleted file mode 100644 index 6211c194..00000000 --- a/docs/solutions/Interviews/words-frequency-lcci.md +++ /dev/null @@ -1,78 +0,0 @@ -# [面试题 16.02. 单词频率](https://leetcode.cn/problems/words-frequency-lcci/) - -- 标签:设计、字典树、数组、哈希表、字符串 -- 难度:中等 - -## 题目链接 - -- [面试题 16.02. 单词频率 - 力扣](https://leetcode.cn/problems/words-frequency-lcci/) - -## 题目大意 - -要求:设计一个方法,找出任意指定单词在一本书中的出现频率。 - -支持如下操作: - -- `WordsFrequency(book)` 构造函数,参数为字符串数组构成的一本书。 -- `get(word)` 查询指定单词在书中出现的频率。 - -## 解题思路 - -使用字典树统计单词频率。 - -构造函数时,构建一个字典树,并将所有单词存入字典树中,同时在字典树中记录并维护单词频率。 - -查询时,调用字典树查询方法,查询单词频率。 - -## 代码 - -```python -class Trie: - - def __init__(self): - """ - Initialize your data structure here. - """ - self.children = dict() - self.isEnd = False - self.count = 0 - - - def insert(self, word: str) -> None: - """ - Inserts a word into the trie. - """ - cur = self - for ch in word: - if ch not in cur.children: - cur.children[ch] = Trie() - cur = cur.children[ch] - cur.isEnd = True - cur.count += 1 - - - def search(self, word: str) -> bool: - """ - Returns if the word is in the trie. - """ - cur = self - for ch in word: - if ch not in cur.children: - return 0 - cur = cur.children[ch] - if cur and cur.isEnd: - return cur.count - return 0 - -class WordsFrequency: - - def __init__(self, book: List[str]): - self.tire_tree = Trie() - for word in book: - self.tire_tree.insert(word) - - - def get(self, word: str) -> int: - return self.tire_tree.search(word) -``` - diff --git a/docs/solutions/Interviews/zero-matrix-lcci.md b/docs/solutions/Interviews/zero-matrix-lcci.md deleted file mode 100644 index 6f9f855b..00000000 --- a/docs/solutions/Interviews/zero-matrix-lcci.md +++ /dev/null @@ -1,70 +0,0 @@ -# [面试题 01.08. 零矩阵](https://leetcode.cn/problems/zero-matrix-lcci/) - -- 标签:数组、哈希表、矩阵 -- 难度:中等 - -## 题目链接 - -- [面试题 01.08. 零矩阵 - 力扣](https://leetcode.cn/problems/zero-matrix-lcci/) - -## 题目大意 - -给定一个 `m * n` 大小的二维矩阵 `matrix`。 - -要求:编写一种算法,如果矩阵中某个元素为 `0`,增将其所在行与列清零。 - -## 解题思路 - -直观上可以使用两个数组或者集合来标记行和列出现 `0` 的情况,但更好的做法是不用开辟新的数组或集合,直接原本二维矩阵 `matrix` 的空间。使用数组原本的元素进行记录出现 0 的情况。 - -设定两个变量 `flag_row0`、`flag_col0` 来标记第一行、第一列是否出现了 `0`。 - -接下来我们使用数组第一行、第一列来标记 `0` 的情况。 - -对数组除第一行、第一列之外的每个元素进行遍历,如果某个元素出现 `0` 了,则使用数组的第一行、第一列对应位置来存储 `0` 的标记。 - -再对数组除第一行、第一列之外的每个元素进行遍历,通过对第一行、第一列的标记 0 情况,进行置为 `0` 的操作。 - -最后再根据 `flag_row0`、`flag_col0` 的标记情况,对第一行、第一列进行置为 `0` 的操作。 - -## 代码 - -```python -class Solution: - def setZeroes(self, matrix: List[List[int]]) -> None: - """ - Do not return anything, modify matrix in-place instead. - """ - rows = len(matrix) - cols = len(matrix[0]) - flag_col0 = False - flag_row0 = False - for i in range(rows): - if matrix[i][0] == 0: - flag_col0 = True - break - - for j in range(cols): - if matrix[0][j] == 0: - flag_row0 = True - break - - for i in range(1, rows): - for j in range(1, cols): - if matrix[i][j] == 0: - matrix[i][0] = matrix[0][j] = 0 - - for i in range(1, rows): - for j in range(1, cols): - if matrix[i][0] == 0 or matrix[0][j] == 0: - matrix[i][j] = 0 - - if flag_col0: - for i in range(rows): - matrix[i][0] = 0 - - if flag_row0: - for j in range(cols): - matrix[0][j] = 0 -``` - From 2f40947008ec02b3a74e7f8ace6506e19280d69c Mon Sep 17 00:00:00 2001 From: ITCharge Date: Tue, 15 Jul 2025 09:16:01 +0800 Subject: [PATCH 2/2] =?UTF-8?q?=E6=9B=B4=E6=94=B9=E9=A2=98=E7=9B=AE?= =?UTF-8?q?=E9=93=BE=E6=8E=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/00_preface/00_05_solutions_list.md | 72 +++++++------- docs/00_preface/00_06_categories_list.md | 4 +- docs/solutions/index.md | 2 +- docs/solutions/interviews/bracket-lcci.md | 45 +++++++++ docs/solutions/interviews/calculator-lcci.md | 66 +++++++++++++ docs/solutions/interviews/color-fill-lcci.md | 66 +++++++++++++ .../solutions/interviews/eight-queens-lcci.md | 77 +++++++++++++++ .../interviews/factorial-zeros-lcci.md | 33 +++++++ .../interviews/first-common-ancestor-lcci.md | 61 ++++++++++++ .../interviews/group-anagrams-lcci.md | 42 ++++++++ .../implement-queue-using-stacks-lcci.md | 74 +++++++++++++++ docs/solutions/interviews/index.md | 32 +++++++ .../intersection-of-two-linked-lists-lcci.md | 54 +++++++++++ .../kth-node-from-end-of-list-lcci.md | 38 ++++++++ .../legal-binary-search-tree-lcci.md | 46 +++++++++ .../interviews/linked-list-cycle-lcci.md | 47 +++++++++ .../solutions/interviews/longest-word-lcci.md | 95 +++++++++++++++++++ docs/solutions/interviews/min-stack-lcci.md | 59 ++++++++++++ .../interviews/minimum-height-tree-lcci.md | 34 +++++++ .../solutions/interviews/multi-search-lcci.md | 80 ++++++++++++++++ .../interviews/number-of-2s-in-range-lcci.md | 85 +++++++++++++++++ .../interviews/palindrome-linked-list-lcci.md | 32 +++++++ .../interviews/paths-with-sum-lcci.md | 45 +++++++++ .../interviews/permutation-i-lcci.md | 46 +++++++++ .../interviews/permutation-ii-lcci.md | 55 +++++++++++ docs/solutions/interviews/power-set-lcci.md | 35 +++++++ .../interviews/rotate-matrix-lcci.md | 67 +++++++++++++ docs/solutions/interviews/smallest-k-lcci.md | 73 ++++++++++++++ .../interviews/sorted-matrix-search-lcci.md | 90 ++++++++++++++++++ .../solutions/interviews/sorted-merge-lcci.md | 72 ++++++++++++++ docs/solutions/interviews/successor-lcci.md | 39 ++++++++ docs/solutions/interviews/sum-lists-lcci.md | 47 +++++++++ .../interviews/words-frequency-lcci.md | 78 +++++++++++++++ docs/solutions/interviews/zero-matrix-lcci.md | 70 ++++++++++++++ 34 files changed, 1822 insertions(+), 39 deletions(-) create mode 100644 docs/solutions/interviews/bracket-lcci.md create mode 100644 docs/solutions/interviews/calculator-lcci.md create mode 100644 docs/solutions/interviews/color-fill-lcci.md create mode 100644 docs/solutions/interviews/eight-queens-lcci.md create mode 100644 docs/solutions/interviews/factorial-zeros-lcci.md create mode 100644 docs/solutions/interviews/first-common-ancestor-lcci.md create mode 100644 docs/solutions/interviews/group-anagrams-lcci.md create mode 100644 docs/solutions/interviews/implement-queue-using-stacks-lcci.md create mode 100644 docs/solutions/interviews/index.md create mode 100644 docs/solutions/interviews/intersection-of-two-linked-lists-lcci.md create mode 100644 docs/solutions/interviews/kth-node-from-end-of-list-lcci.md create mode 100644 docs/solutions/interviews/legal-binary-search-tree-lcci.md create mode 100644 docs/solutions/interviews/linked-list-cycle-lcci.md create mode 100644 docs/solutions/interviews/longest-word-lcci.md create mode 100644 docs/solutions/interviews/min-stack-lcci.md create mode 100644 docs/solutions/interviews/minimum-height-tree-lcci.md create mode 100644 docs/solutions/interviews/multi-search-lcci.md create mode 100644 docs/solutions/interviews/number-of-2s-in-range-lcci.md create mode 100644 docs/solutions/interviews/palindrome-linked-list-lcci.md create mode 100644 docs/solutions/interviews/paths-with-sum-lcci.md create mode 100644 docs/solutions/interviews/permutation-i-lcci.md create mode 100644 docs/solutions/interviews/permutation-ii-lcci.md create mode 100644 docs/solutions/interviews/power-set-lcci.md create mode 100644 docs/solutions/interviews/rotate-matrix-lcci.md create mode 100644 docs/solutions/interviews/smallest-k-lcci.md create mode 100644 docs/solutions/interviews/sorted-matrix-search-lcci.md create mode 100644 docs/solutions/interviews/sorted-merge-lcci.md create mode 100644 docs/solutions/interviews/successor-lcci.md create mode 100644 docs/solutions/interviews/sum-lists-lcci.md create mode 100644 docs/solutions/interviews/words-frequency-lcci.md create mode 100644 docs/solutions/interviews/zero-matrix-lcci.md diff --git a/docs/00_preface/00_05_solutions_list.md b/docs/00_preface/00_05_solutions_list.md index 8d180da6..9f504ed7 100644 --- a/docs/00_preface/00_05_solutions_list.md +++ b/docs/00_preface/00_05_solutions_list.md @@ -822,42 +822,6 @@ | [2719. 统计整数数目](https://leetcode.cn/problems/count-of-integers/) | [题解](https://github.com/ITCharge/AlgoNote/tree/main/docs/solutions/2700-2799/count-of-integers.md) | 数学、字符串、动态规划 | 困难 | -### 面试题 - -| 标题 | 题解 | 标签 | 难度 | -| :--- | :--- | :--- | :--- | -| [面试题 01.07. 旋转矩阵](https://leetcode.cn/problems/rotate-matrix-lcci/) | [题解](https://github.com/ITCharge/AlgoNote/tree/main/docs/solutions/Interviews/rotate-matrix-lcci.md) | 数组、数学、矩阵 | 中等 | -| [面试题 01.08. 零矩阵](https://leetcode.cn/problems/zero-matrix-lcci/) | [题解](https://github.com/ITCharge/AlgoNote/tree/main/docs/solutions/Interviews/zero-matrix-lcci.md) | 数组、哈希表、矩阵 | 中等 | -| [面试题 02.02. 返回倒数第 k 个节点](https://leetcode.cn/problems/kth-node-from-end-of-list-lcci/) | [题解](https://github.com/ITCharge/AlgoNote/tree/main/docs/solutions/Interviews/kth-node-from-end-of-list-lcci.md) | 链表、双指针 | 简单 | -| [面试题 02.05. 链表求和](https://leetcode.cn/problems/sum-lists-lcci/) | [题解](https://github.com/ITCharge/AlgoNote/tree/main/docs/solutions/Interviews/sum-lists-lcci.md) | 递归、链表、数学 | 中等 | -| [面试题 02.06. 回文链表](https://leetcode.cn/problems/palindrome-linked-list-lcci/) | [题解](https://github.com/ITCharge/AlgoNote/tree/main/docs/solutions/Interviews/palindrome-linked-list-lcci.md) | 栈、递归、链表、双指针 | 简单 | -| [面试题 02.07. 链表相交](https://leetcode.cn/problems/intersection-of-two-linked-lists-lcci/) | [题解](https://github.com/ITCharge/AlgoNote/tree/main/docs/solutions/Interviews/intersection-of-two-linked-lists-lcci.md) | 哈希表、链表、双指针 | 简单 | -| [面试题 02.08. 环路检测](https://leetcode.cn/problems/linked-list-cycle-lcci/) | [题解](https://github.com/ITCharge/AlgoNote/tree/main/docs/solutions/Interviews/linked-list-cycle-lcci.md) | 哈希表、链表、双指针 | 中等 | -| [面试题 03.02. 栈的最小值](https://leetcode.cn/problems/min-stack-lcci/) | [题解](https://github.com/ITCharge/AlgoNote/tree/main/docs/solutions/Interviews/min-stack-lcci.md) | 栈、设计 | 简单 | -| [面试题 03.04. 化栈为队](https://leetcode.cn/problems/implement-queue-using-stacks-lcci/) | [题解](https://github.com/ITCharge/AlgoNote/tree/main/docs/solutions/Interviews/implement-queue-using-stacks-lcci.md) | 栈、设计、队列 | 简单 | -| [面试题 04.02. 最小高度树](https://leetcode.cn/problems/minimum-height-tree-lcci/) | [题解](https://github.com/ITCharge/AlgoNote/tree/main/docs/solutions/Interviews/minimum-height-tree-lcci.md) | 树、二叉搜索树、数组、分治、二叉树 | 简单 | -| [面试题 04.05. 合法二叉搜索树](https://leetcode.cn/problems/legal-binary-search-tree-lcci/) | [题解](https://github.com/ITCharge/AlgoNote/tree/main/docs/solutions/Interviews/legal-binary-search-tree-lcci.md) | 树、深度优先搜索、二叉搜索树、二叉树 | 中等 | -| [面试题 04.06. 后继者](https://leetcode.cn/problems/successor-lcci/) | [题解](https://github.com/ITCharge/AlgoNote/tree/main/docs/solutions/Interviews/successor-lcci.md) | 树、深度优先搜索、二叉搜索树、二叉树 | 中等 | -| [面试题 04.08. 首个共同祖先](https://leetcode.cn/problems/first-common-ancestor-lcci/) | [题解](https://github.com/ITCharge/AlgoNote/tree/main/docs/solutions/Interviews/first-common-ancestor-lcci.md) | 树、深度优先搜索、二叉树 | 中等 | -| [面试题 04.12. 求和路径](https://leetcode.cn/problems/paths-with-sum-lcci/) | [题解](https://github.com/ITCharge/AlgoNote/tree/main/docs/solutions/Interviews/paths-with-sum-lcci.md) | 树、深度优先搜索、二叉树 | 中等 | -| [面试题 08.04. 幂集](https://leetcode.cn/problems/power-set-lcci/) | [题解](https://github.com/ITCharge/AlgoNote/tree/main/docs/solutions/Interviews/power-set-lcci.md) | 位运算、数组、回溯 | 中等 | -| [面试题 08.07. 无重复字符串的排列组合](https://leetcode.cn/problems/permutation-i-lcci/) | [题解](https://github.com/ITCharge/AlgoNote/tree/main/docs/solutions/Interviews/permutation-i-lcci.md) | 字符串、回溯 | 中等 | -| [面试题 08.08. 有重复字符串的排列组合](https://leetcode.cn/problems/permutation-ii-lcci/) | [题解](https://github.com/ITCharge/AlgoNote/tree/main/docs/solutions/Interviews/permutation-ii-lcci.md) | 字符串、回溯 | 中等 | -| [面试题 08.09. 括号](https://leetcode.cn/problems/bracket-lcci/) | [题解](https://github.com/ITCharge/AlgoNote/tree/main/docs/solutions/Interviews/bracket-lcci.md) | 字符串、动态规划、回溯 | 中等 | -| [面试题 08.10. 颜色填充](https://leetcode.cn/problems/color-fill-lcci/) | [题解](https://github.com/ITCharge/AlgoNote/tree/main/docs/solutions/Interviews/color-fill-lcci.md) | 深度优先搜索、广度优先搜索、数组、矩阵 | 简单 | -| [面试题 08.12. 八皇后](https://leetcode.cn/problems/eight-queens-lcci/) | [题解](https://github.com/ITCharge/AlgoNote/tree/main/docs/solutions/Interviews/eight-queens-lcci.md) | 数组、回溯 | 困难 | -| [面试题 10.01. 合并排序的数组](https://leetcode.cn/problems/sorted-merge-lcci/) | [题解](https://github.com/ITCharge/AlgoNote/tree/main/docs/solutions/Interviews/sorted-merge-lcci.md) | 数组、双指针、排序 | 简单 | -| [面试题 10.02. 变位词组](https://leetcode.cn/problems/group-anagrams-lcci/) | [题解](https://github.com/ITCharge/AlgoNote/tree/main/docs/solutions/Interviews/group-anagrams-lcci.md) | 数组、哈希表、字符串、排序 | 中等 | -| [面试题 10.09. 排序矩阵查找](https://leetcode.cn/problems/sorted-matrix-search-lcci/) | [题解](https://github.com/ITCharge/AlgoNote/tree/main/docs/solutions/Interviews/sorted-matrix-search-lcci.md) | 数组、二分查找、分治、矩阵 | 中等 | -| [面试题 16.02. 单词频率](https://leetcode.cn/problems/words-frequency-lcci/) | [题解](https://github.com/ITCharge/AlgoNote/tree/main/docs/solutions/Interviews/words-frequency-lcci.md) | 设计、字典树、数组、哈希表、字符串 | 中等 | -| [面试题 16.05. 阶乘尾数](https://leetcode.cn/problems/factorial-zeros-lcci/) | [题解](https://github.com/ITCharge/AlgoNote/tree/main/docs/solutions/Interviews/factorial-zeros-lcci.md) | 数学 | 简单 | -| [面试题 16.26. 计算器](https://leetcode.cn/problems/calculator-lcci/) | [题解](https://github.com/ITCharge/AlgoNote/tree/main/docs/solutions/Interviews/calculator-lcci.md) | 栈、数学、字符串 | 中等 | -| [面试题 17.06. 2出现的次数](https://leetcode.cn/problems/number-of-2s-in-range-lcci/) | [题解](https://github.com/ITCharge/AlgoNote/tree/main/docs/solutions/Interviews/number-of-2s-in-range-lcci.md) | 递归、数学、动态规划 | 困难 | -| [面试题 17.14. 最小K个数](https://leetcode.cn/problems/smallest-k-lcci/) | [题解](https://github.com/ITCharge/AlgoNote/tree/main/docs/solutions/Interviews/smallest-k-lcci.md) | 数组、分治、快速选择、排序、堆(优先队列) | 中等 | -| [面试题 17.15. 最长单词](https://leetcode.cn/problems/longest-word-lcci/) | [题解](https://github.com/ITCharge/AlgoNote/tree/main/docs/solutions/Interviews/longest-word-lcci.md) | 字典树、数组、哈希表、字符串 | 中等 | -| [面试题 17.17. 多次搜索](https://leetcode.cn/problems/multi-search-lcci/) | [题解](https://github.com/ITCharge/AlgoNote/tree/main/docs/solutions/Interviews/multi-search-lcci.md) | 字典树、数组、哈希表、字符串、字符串匹配、滑动窗口 | 中等 | - - ### LCR 系列 | 标题 | 题解 | 标签 | 难度 | @@ -1034,3 +998,39 @@ | [LCR 194. 二叉树的最近公共祖先](https://leetcode.cn/problems/er-cha-shu-de-zui-jin-gong-gong-zu-xian-lcof/) | [题解](https://github.com/ITCharge/AlgoNote/tree/main/docs/solutions/LCR/er-cha-shu-de-zui-jin-gong-gong-zu-xian-lcof.md) | 树、深度优先搜索、二叉树 | 简单 | +### 面试题 + +| 标题 | 题解 | 标签 | 难度 | +| :--- | :--- | :--- | :--- | +| [面试题 01.07. 旋转矩阵](https://leetcode.cn/problems/rotate-matrix-lcci/) | [题解](https://github.com/ITCharge/AlgoNote/tree/main/docs/solutions/interviews/rotate-matrix-lcci.md) | 数组、数学、矩阵 | 中等 | +| [面试题 01.08. 零矩阵](https://leetcode.cn/problems/zero-matrix-lcci/) | [题解](https://github.com/ITCharge/AlgoNote/tree/main/docs/solutions/interviews/zero-matrix-lcci.md) | 数组、哈希表、矩阵 | 中等 | +| [面试题 02.02. 返回倒数第 k 个节点](https://leetcode.cn/problems/kth-node-from-end-of-list-lcci/) | [题解](https://github.com/ITCharge/AlgoNote/tree/main/docs/solutions/interviews/kth-node-from-end-of-list-lcci.md) | 链表、双指针 | 简单 | +| [面试题 02.05. 链表求和](https://leetcode.cn/problems/sum-lists-lcci/) | [题解](https://github.com/ITCharge/AlgoNote/tree/main/docs/solutions/interviews/sum-lists-lcci.md) | 递归、链表、数学 | 中等 | +| [面试题 02.06. 回文链表](https://leetcode.cn/problems/palindrome-linked-list-lcci/) | [题解](https://github.com/ITCharge/AlgoNote/tree/main/docs/solutions/interviews/palindrome-linked-list-lcci.md) | 栈、递归、链表、双指针 | 简单 | +| [面试题 02.07. 链表相交](https://leetcode.cn/problems/intersection-of-two-linked-lists-lcci/) | [题解](https://github.com/ITCharge/AlgoNote/tree/main/docs/solutions/interviews/intersection-of-two-linked-lists-lcci.md) | 哈希表、链表、双指针 | 简单 | +| [面试题 02.08. 环路检测](https://leetcode.cn/problems/linked-list-cycle-lcci/) | [题解](https://github.com/ITCharge/AlgoNote/tree/main/docs/solutions/interviews/linked-list-cycle-lcci.md) | 哈希表、链表、双指针 | 中等 | +| [面试题 03.02. 栈的最小值](https://leetcode.cn/problems/min-stack-lcci/) | [题解](https://github.com/ITCharge/AlgoNote/tree/main/docs/solutions/interviews/min-stack-lcci.md) | 栈、设计 | 简单 | +| [面试题 03.04. 化栈为队](https://leetcode.cn/problems/implement-queue-using-stacks-lcci/) | [题解](https://github.com/ITCharge/AlgoNote/tree/main/docs/solutions/interviews/implement-queue-using-stacks-lcci.md) | 栈、设计、队列 | 简单 | +| [面试题 04.02. 最小高度树](https://leetcode.cn/problems/minimum-height-tree-lcci/) | [题解](https://github.com/ITCharge/AlgoNote/tree/main/docs/solutions/interviews/minimum-height-tree-lcci.md) | 树、二叉搜索树、数组、分治、二叉树 | 简单 | +| [面试题 04.05. 合法二叉搜索树](https://leetcode.cn/problems/legal-binary-search-tree-lcci/) | [题解](https://github.com/ITCharge/AlgoNote/tree/main/docs/solutions/interviews/legal-binary-search-tree-lcci.md) | 树、深度优先搜索、二叉搜索树、二叉树 | 中等 | +| [面试题 04.06. 后继者](https://leetcode.cn/problems/successor-lcci/) | [题解](https://github.com/ITCharge/AlgoNote/tree/main/docs/solutions/interviews/successor-lcci.md) | 树、深度优先搜索、二叉搜索树、二叉树 | 中等 | +| [面试题 04.08. 首个共同祖先](https://leetcode.cn/problems/first-common-ancestor-lcci/) | [题解](https://github.com/ITCharge/AlgoNote/tree/main/docs/solutions/interviews/first-common-ancestor-lcci.md) | 树、深度优先搜索、二叉树 | 中等 | +| [面试题 04.12. 求和路径](https://leetcode.cn/problems/paths-with-sum-lcci/) | [题解](https://github.com/ITCharge/AlgoNote/tree/main/docs/solutions/interviews/paths-with-sum-lcci.md) | 树、深度优先搜索、二叉树 | 中等 | +| [面试题 08.04. 幂集](https://leetcode.cn/problems/power-set-lcci/) | [题解](https://github.com/ITCharge/AlgoNote/tree/main/docs/solutions/interviews/power-set-lcci.md) | 位运算、数组、回溯 | 中等 | +| [面试题 08.07. 无重复字符串的排列组合](https://leetcode.cn/problems/permutation-i-lcci/) | [题解](https://github.com/ITCharge/AlgoNote/tree/main/docs/solutions/interviews/permutation-i-lcci.md) | 字符串、回溯 | 中等 | +| [面试题 08.08. 有重复字符串的排列组合](https://leetcode.cn/problems/permutation-ii-lcci/) | [题解](https://github.com/ITCharge/AlgoNote/tree/main/docs/solutions/interviews/permutation-ii-lcci.md) | 字符串、回溯 | 中等 | +| [面试题 08.09. 括号](https://leetcode.cn/problems/bracket-lcci/) | [题解](https://github.com/ITCharge/AlgoNote/tree/main/docs/solutions/interviews/bracket-lcci.md) | 字符串、动态规划、回溯 | 中等 | +| [面试题 08.10. 颜色填充](https://leetcode.cn/problems/color-fill-lcci/) | [题解](https://github.com/ITCharge/AlgoNote/tree/main/docs/solutions/interviews/color-fill-lcci.md) | 深度优先搜索、广度优先搜索、数组、矩阵 | 简单 | +| [面试题 08.12. 八皇后](https://leetcode.cn/problems/eight-queens-lcci/) | [题解](https://github.com/ITCharge/AlgoNote/tree/main/docs/solutions/interviews/eight-queens-lcci.md) | 数组、回溯 | 困难 | +| [面试题 10.01. 合并排序的数组](https://leetcode.cn/problems/sorted-merge-lcci/) | [题解](https://github.com/ITCharge/AlgoNote/tree/main/docs/solutions/interviews/sorted-merge-lcci.md) | 数组、双指针、排序 | 简单 | +| [面试题 10.02. 变位词组](https://leetcode.cn/problems/group-anagrams-lcci/) | [题解](https://github.com/ITCharge/AlgoNote/tree/main/docs/solutions/interviews/group-anagrams-lcci.md) | 数组、哈希表、字符串、排序 | 中等 | +| [面试题 10.09. 排序矩阵查找](https://leetcode.cn/problems/sorted-matrix-search-lcci/) | [题解](https://github.com/ITCharge/AlgoNote/tree/main/docs/solutions/interviews/sorted-matrix-search-lcci.md) | 数组、二分查找、分治、矩阵 | 中等 | +| [面试题 16.02. 单词频率](https://leetcode.cn/problems/words-frequency-lcci/) | [题解](https://github.com/ITCharge/AlgoNote/tree/main/docs/solutions/interviews/words-frequency-lcci.md) | 设计、字典树、数组、哈希表、字符串 | 中等 | +| [面试题 16.05. 阶乘尾数](https://leetcode.cn/problems/factorial-zeros-lcci/) | [题解](https://github.com/ITCharge/AlgoNote/tree/main/docs/solutions/interviews/factorial-zeros-lcci.md) | 数学 | 简单 | +| [面试题 16.26. 计算器](https://leetcode.cn/problems/calculator-lcci/) | [题解](https://github.com/ITCharge/AlgoNote/tree/main/docs/solutions/interviews/calculator-lcci.md) | 栈、数学、字符串 | 中等 | +| [面试题 17.06. 2出现的次数](https://leetcode.cn/problems/number-of-2s-in-range-lcci/) | [题解](https://github.com/ITCharge/AlgoNote/tree/main/docs/solutions/interviews/number-of-2s-in-range-lcci.md) | 递归、数学、动态规划 | 困难 | +| [面试题 17.14. 最小K个数](https://leetcode.cn/problems/smallest-k-lcci/) | [题解](https://github.com/ITCharge/AlgoNote/tree/main/docs/solutions/interviews/smallest-k-lcci.md) | 数组、分治、快速选择、排序、堆(优先队列) | 中等 | +| [面试题 17.15. 最长单词](https://leetcode.cn/problems/longest-word-lcci/) | [题解](https://github.com/ITCharge/AlgoNote/tree/main/docs/solutions/interviews/longest-word-lcci.md) | 字典树、数组、哈希表、字符串 | 中等 | +| [面试题 17.17. 多次搜索](https://leetcode.cn/problems/multi-search-lcci/) | [题解](https://github.com/ITCharge/AlgoNote/tree/main/docs/solutions/interviews/multi-search-lcci.md) | 字典树、数组、哈希表、字符串、字符串匹配、滑动窗口 | 中等 | + + diff --git a/docs/00_preface/00_06_categories_list.md b/docs/00_preface/00_06_categories_list.md index 6be90eb5..8c01d8c3 100644 --- a/docs/00_preface/00_06_categories_list.md +++ b/docs/00_preface/00_06_categories_list.md @@ -979,7 +979,7 @@ | [0576. 出界的路径数](https://leetcode.cn/problems/out-of-boundary-paths/) | [题解](https://github.com/ITCharge/AlgoNote/tree/main/docs/solutions/0500-0599/out-of-boundary-paths.md) | 动态规划 | 中等 | | [0085. 最大矩形](https://leetcode.cn/problems/maximal-rectangle/) | [题解](https://github.com/ITCharge/AlgoNote/tree/main/docs/solutions/0001-0099/maximal-rectangle.md) | 栈、数组、动态规划、矩阵、单调栈 | 困难 | | [0363. 矩形区域不超过 K 的最大数值和](https://leetcode.cn/problems/max-sum-of-rectangle-no-larger-than-k/) | [题解](https://github.com/ITCharge/AlgoNote/tree/main/docs/solutions/0300-0399/max-sum-of-rectangle-no-larger-than-k.md) | 数组、二分查找、矩阵、有序集合、前缀和 | 困难 | -| [面试题 17.24. 最大子矩阵](https://leetcode.cn/problems/max-submatrix-lcci/) | [题解](https://github.com/ITCharge/AlgoNote/tree/main/docs/solutions/Interviews/max-submatrix-lcci.md) | 数组、动态规划、矩阵、前缀和 | 困难 | +| [面试题 17.24. 最大子矩阵](https://leetcode.cn/problems/max-submatrix-lcci/) | [题解](https://github.com/ITCharge/AlgoNote/tree/main/docs/solutions/interviews/max-submatrix-lcci.md) | 数组、动态规划、矩阵、前缀和 | 困难 | | [1444. 切披萨的方案数](https://leetcode.cn/problems/number-of-ways-of-cutting-a-pizza/) | [题解](https://github.com/ITCharge/AlgoNote/tree/main/docs/solutions/1400-1499/number-of-ways-of-cutting-a-pizza.md) | 记忆化搜索、数组、动态规划、矩阵、前缀和 | 困难 | @@ -1148,7 +1148,7 @@ | [1088. 易混淆数 II](https://leetcode.cn/problems/confusing-number-ii/) | [题解](https://github.com/ITCharge/AlgoNote/tree/main/docs/solutions/1000-1099/confusing-number-ii.md) | 数学、回溯 | 困难 | | [1067. 范围内的数字计数](https://leetcode.cn/problems/digit-count-in-range/) | [题解](https://github.com/ITCharge/AlgoNote/tree/main/docs/solutions/1000-1099/digit-count-in-range.md) | 数学、动态规划 | 困难 | | [1742. 盒子中小球的最大数量](https://leetcode.cn/problems/maximum-number-of-balls-in-a-box/) | [题解](https://github.com/ITCharge/AlgoNote/tree/main/docs/solutions/1700-1799/maximum-number-of-balls-in-a-box.md) | 哈希表、数学、计数 | 简单 | -| [面试题 17.06. 2出现的次数](https://leetcode.cn/problems/number-of-2s-in-range-lcci/) | [题解](https://github.com/ITCharge/AlgoNote/tree/main/docs/solutions/Interviews/number-of-2s-in-range-lcci.md) | 递归、数学、动态规划 | 困难 | +| [面试题 17.06. 2出现的次数](https://leetcode.cn/problems/number-of-2s-in-range-lcci/) | [题解](https://github.com/ITCharge/AlgoNote/tree/main/docs/solutions/interviews/number-of-2s-in-range-lcci.md) | 递归、数学、动态规划 | 困难 | ### 概率 DP 题目 diff --git a/docs/solutions/index.md b/docs/solutions/index.md index 6e892b6f..2b2745ad 100644 --- a/docs/solutions/index.md +++ b/docs/solutions/index.md @@ -27,5 +27,5 @@ - [第 2400 ~ 2499 题](https://github.com/ITCharge/AlgoNote/tree/main/docs/solutions/2400-2499/) - [第 2500 ~ 2599 题](https://github.com/ITCharge/AlgoNote/tree/main/docs/solutions/2500-2599/) - [第 2700 ~ 2799 题](https://github.com/ITCharge/AlgoNote/tree/main/docs/solutions/2700-2799/) -- [面试题](https://github.com/ITCharge/AlgoNote/tree/main/docs/solutions/Interviews/) - [LCR 系列](https://github.com/ITCharge/AlgoNote/tree/main/docs/solutions/LCR/) +- [面试题](https://github.com/ITCharge/AlgoNote/tree/main/docs/solutions/interviews/) diff --git a/docs/solutions/interviews/bracket-lcci.md b/docs/solutions/interviews/bracket-lcci.md new file mode 100644 index 00000000..afb671f1 --- /dev/null +++ b/docs/solutions/interviews/bracket-lcci.md @@ -0,0 +1,45 @@ +# [面试题 08.09. 括号](https://leetcode.cn/problems/bracket-lcci/) + +- 标签:字符串、动态规划、回溯 +- 难度:中等 + +## 题目链接 + +- [面试题 08.09. 括号 - 力扣](https://leetcode.cn/problems/bracket-lcci/) + +## 题目大意 + +给定一个整数 `n`。 + +要求:生成所有有可能且有效的括号组合。 + +## 解题思路 + +通过回溯算法生成所有答案。为了生成的括号组合是有效的,回溯的时候,使用一个标记变量 `symbol` 来表示是否当前组合是否成对匹配。 + +如果在当前组合中增加一个 `(`,则 `symbol += 1`,如果增加一个 `)`,则 `symbol -= 1`。显然只有在 `symbol < n` 的时候,才能增加 `(`,在 `symbol > 0` 的时候,才能增加 `)`。 + +如果最终生成 `2 * n` 的括号组合,并且 `symbol == 0`,则说明当前组合是有效的,将其加入到最终答案数组中。 + +最终输出最终答案数组。 + +## 代码 + +```python +class Solution: + def generateParenthesis(self, n: int) -> List[str]: + def backtrack(parenthesis, symbol, index): + if n * 2 == index: + if symbol == 0: + parentheses.append(parenthesis) + else: + if symbol < n: + backtrack(parenthesis + '(', symbol + 1, index + 1) + if symbol > 0: + backtrack(parenthesis + ')', symbol - 1, index + 1) + + parentheses = list() + backtrack("", 0, 0) + return parentheses +``` + diff --git a/docs/solutions/interviews/calculator-lcci.md b/docs/solutions/interviews/calculator-lcci.md new file mode 100644 index 00000000..ce90dafb --- /dev/null +++ b/docs/solutions/interviews/calculator-lcci.md @@ -0,0 +1,66 @@ +# [面试题 16.26. 计算器](https://leetcode.cn/problems/calculator-lcci/) + +- 标签:栈、数学、字符串 +- 难度:中等 + +## 题目链接 + +- [面试题 16.26. 计算器 - 力扣](https://leetcode.cn/problems/calculator-lcci/) + +## 题目大意 + +给定一个包含正整数、加(`+`)、减(`-`)、乘(`*`)、除(`/`)的算出表达式(括号除外)。表达式仅包含非负整数,`+`、`-`、`*`、`/` 四种运算符和空格 ` `。整数除法仅保留整数部分。 + +要求:计算其结果。 + +## 解题思路 + +计算表达式中,乘除运算优先于加减运算。我们可以先进行乘除运算,再将进行乘除运算后的整数值放入原表达式中相应位置,再依次计算加减。 + +可以考虑使用一个栈来保存进行乘除运算后的整数值。正整数直接压入栈中,负整数,则将对应整数取负号,再压入栈中。这样最终计算结果就是栈中所有元素的和。 + +具体做法: + +- 遍历字符串 s,使用变量 op 来标记数字之前的运算符,默认为 `+`。 +- 如果遇到数字,继续向后遍历,将数字进行累积,得到完整的整数 num。判断当前 op 的符号。 + - 如果 op 为 `+`,则将 num 压入栈中。 + - 如果 op 为 `-`,则将 -num 压入栈中。 + - 如果 op 为 `*`,则将栈顶元素 top 取出,计算 top * num,并将计算结果压入栈中。 + - 如果 op 为 `/`,则将栈顶元素 top 取出,计算 int(top / num),并将计算结果压入栈中。 +- 如果遇到 `+`、`-`、`*`、`/` 操作符,则更新 op。 +- 最后将栈中整数进行累加,并返回结果。 + +## 代码 + +```python +class Solution: + def calculate(self, s: str) -> int: + size = len(s) + stack = [] + op = '+' + index = 0 + while index < size: + if s[index] == ' ': + index += 1 + continue + if s[index].isdigit(): + num = ord(s[index]) - ord('0') + while index + 1 < size and s[index + 1].isdigit(): + index += 1 + num = 10 * num + ord(s[index]) - ord('0') + if op == '+': + stack.append(num) + elif op == '-': + stack.append(-num) + elif op == '*': + top = stack.pop() + stack.append(top * num) + elif op == '/': + top = stack.pop() + stack.append(int(top / num)) + elif s[index] in "+-*/": + op = s[index] + index += 1 + return sum(stack) +``` + diff --git a/docs/solutions/interviews/color-fill-lcci.md b/docs/solutions/interviews/color-fill-lcci.md new file mode 100644 index 00000000..0581382e --- /dev/null +++ b/docs/solutions/interviews/color-fill-lcci.md @@ -0,0 +1,66 @@ +# [面试题 08.10. 颜色填充](https://leetcode.cn/problems/color-fill-lcci/) + +- 标签:深度优先搜索、广度优先搜索、数组、矩阵 +- 难度:简单 + +## 题目链接 + +- [面试题 08.10. 颜色填充 - 力扣](https://leetcode.cn/problems/color-fill-lcci/) + +## 题目大意 + +给定一个二维整数矩阵 `image`,其中 `image[i][j]` 表示矩阵第 `i` 行、第 `j` 列上网格块的颜色值。再给定一个起始位置 `(sr, sc)`,以及一个目标颜色 `newColor`。 + +要求:对起始位置 `(sr, sc)` 所在位置周围区域填充颜色为 `newColor`。并返回填充后的图像 `image`。 + +- 周围区域:颜色相同且在上、下、左、右四个方向上存在相连情况的若干元素。 + +## 解题思路 + +深度优先搜索。使用二维数组 `visited` 标记访问过的节点。遍历上、下、左、右四个方向上的点。如果下一个点位置越界,或者当前位置与下一个点位置颜色不一样,则对该节点进行染色。 + +在遍历的过程中注意使用 `visited` 标记访问过的节点,以免重复遍历。 + +## 代码 + +```python +class Solution: + directs = [(0, 1), (0, -1), (1, 0), (-1, 0)] + + def dfs(self, image, i, j, origin_color, color, visited): + rows, cols = len(image), len(image[0]) + + for direct in self.directs: + new_i = i + direct[0] + new_j = j + direct[1] + + # 下一个位置越界,则当前点在边界,对其进行着色 + if new_i < 0 or new_i >= rows or new_j < 0 or new_j >= cols: + image[i][j] = color + continue + + # 如果访问过,则跳过 + if visited[new_i][new_j]: + continue + + # 如果下一个位置颜色与当前颜色相同,则继续搜索 + if image[new_i][new_j] == origin_color: + visited[new_i][new_j] = True + self.dfs(image, new_i, new_j, origin_color, color, visited) + # 下一个位置颜色与当前颜色不同,则当前位置为连通区域边界,对其进行着色 + else: + image[i][j] = color + + def floodFill(self, image: List[List[int]], sr: int, sc: int, newColor: int) -> List[List[int]]: + if not image: + return image + + rows, cols = len(image), len(image[0]) + visited = [[False for _ in range(cols)] for _ in range(rows)] + visited[sr][sc] = True + + self.dfs(image, sr, sc, image[sr][sc], newColor, visited) + + return image +``` + diff --git a/docs/solutions/interviews/eight-queens-lcci.md b/docs/solutions/interviews/eight-queens-lcci.md new file mode 100644 index 00000000..d1447849 --- /dev/null +++ b/docs/solutions/interviews/eight-queens-lcci.md @@ -0,0 +1,77 @@ +# [面试题 08.12. 八皇后](https://leetcode.cn/problems/eight-queens-lcci/) + +- 标签:数组、回溯 +- 难度:困难 + +## 题目链接 + +- [面试题 08.12. 八皇后 - 力扣](https://leetcode.cn/problems/eight-queens-lcci/) + +## 题目大意 + +- n 皇后问题:将 n 个皇后放置在 `n * n` 的棋盘上,并且使得皇后彼此之间不能攻击。 +- 皇后彼此不能相互攻击:指的是任何两个皇后都不能处于同一条横线、纵线或者斜线上。 + +现在给定一个整数 `n`,返回所有不同的「n 皇后问题」的解决方案。每一种解法包含一个不同的「n 皇后问题」的棋子放置方案,该方案中的 `Q` 和 `.` 分别代表了皇后和空位。 + +## 解题思路 + +经典的回溯问题。使用 `chessboard` 来表示棋盘,`Q` 代表皇后,`.` 代表空位,初始都为 `.`。然后使用 `res` 存放最终答案。 + +先定义棋盘合理情况判断方法,判断同一条横线、纵线或者斜线上是否存在两个以上的皇后。 + +再定义回溯方法,从第一行开始进行遍历。 + +- 如果当前行 `row` 等于 `n`,则当前棋盘为一个可行方案,将其拼接加入到 `res` 数组中。 +- 遍历 `[0, n]` 列元素,先验证棋盘是否可行,如果可行: + - 将当前行当前列尝试换为 `Q`。 + - 然后继续递归下一行。 + - 再将当前行回退为 `.`。 +- 最终返回 `res` 数组。 + +## 代码 + +```python +class Solution: + res = [] + def backtrack(self, n: int, row: int, chessboard: List[List[str]]): + if row == n: + temp_res = [] + for temp in chessboard: + temp_str = ''.join(temp) + temp_res.append(temp_str) + self.res.append(temp_res) + return + for col in range(n): + if self.isValid(n, row, col, chessboard): + chessboard[row][col] = 'Q' + self.backtrack(n, row + 1, chessboard) + chessboard[row][col] = '.' + + def isValid(self, n: int, row: int, col: int, chessboard: List[List[str]]): + for i in range(row): + if chessboard[i][col] == 'Q': + return False + + i, j = row - 1, col - 1 + while i >= 0 and j >= 0: + if chessboard[i][j] == 'Q': + return False + i -= 1 + j -= 1 + i, j = row - 1, col + 1 + while i >= 0 and j < n: + if chessboard[i][j] == 'Q': + return False + i -= 1 + j += 1 + + return True + + def solveNQueens(self, n: int) -> List[List[str]]: + self.res.clear() + chessboard = [['.' for _ in range(n)] for _ in range(n)] + self.backtrack(n, 0, chessboard) + return self.res +``` + diff --git a/docs/solutions/interviews/factorial-zeros-lcci.md b/docs/solutions/interviews/factorial-zeros-lcci.md new file mode 100644 index 00000000..6f3f8770 --- /dev/null +++ b/docs/solutions/interviews/factorial-zeros-lcci.md @@ -0,0 +1,33 @@ +# [面试题 16.05. 阶乘尾数](https://leetcode.cn/problems/factorial-zeros-lcci/) + +- 标签:数学 +- 难度:简单 + +## 题目链接 + +- [面试题 16.05. 阶乘尾数 - 力扣](https://leetcode.cn/problems/factorial-zeros-lcci/) + +## 题目大意 + +给定一个整数 `n`。 + +要求:计算 `n` 的阶乘中尾随零的数量。 + +注意:$0 <= n <= 10^4$。 + +## 解题思路 + +阶乘中,末尾 `0` 的来源只有 `2 * 5`。所以尾随 `0` 的个数为 `2` 的倍数个数和 `5` 的倍数个数的最小值。又因为 `2 < 5`,`2` 的倍数个数肯定小于等于 `5` 的倍数,所以直接统计 `5` 的倍数个数即可。 + +## 代码 + +```python +class Solution: + def trailingZeroes(self, n: int) -> int: + count = 0 + while n > 0: + count += n // 5 + n = n // 5 + return count +``` + diff --git a/docs/solutions/interviews/first-common-ancestor-lcci.md b/docs/solutions/interviews/first-common-ancestor-lcci.md new file mode 100644 index 00000000..f1fb498b --- /dev/null +++ b/docs/solutions/interviews/first-common-ancestor-lcci.md @@ -0,0 +1,61 @@ +# [面试题 04.08. 首个共同祖先](https://leetcode.cn/problems/first-common-ancestor-lcci/) + +- 标签:树、深度优先搜索、二叉树 +- 难度:中等 + +## 题目链接 + +- [面试题 04.08. 首个共同祖先 - 力扣](https://leetcode.cn/problems/first-common-ancestor-lcci/) + +## 题目大意 + +给定一个二叉树,要求找到该树中指定节点 `p`、`q` 的最近公共祖先: + +- 祖先:若节点 `p` 在节点 `node` 的左子树或右子树中,或者 `p = node`,则称 `node` 是 `p` 的祖先。 + +- 最近公共祖先:对于树的两个节点 `p`、`q`,最近公共祖先表示为一个节点 `lca_node`,满足 `lca_node` 是 `p`、`q` 的祖先且 `lca_node` 的深度尽可能大(一个节点也可以是自己的祖先)。 + +## 解题思路 + +设 `lca_node` 为节点 `p`、`q` 的最近公共祖先。则 `lca_node` 只能是下面几种情况: + +- `p`、`q` 在 `lca_node` 的子树中,且分别在 `lca_node` 的两侧子树中。 +- `p == lca_node`,且 `q` 在 `lca_node` 的左子树或右子树中。 +- `q == lca_node`,且 `p` 在 `lca_node` 的左子树或右子树中。 + +下面递归求解 `lca_node`。递归需要满足以下条件: + +- 如果 `p`、`q` 都不为空,则返回 `p`、`q` 的公共祖先。 +- 如果 `p`、`q` 只有一个存在,则返回存在的一个。 +- 如果 `p`、`q` 都不存在,则返回存在的一个。 + +具体思路为: + +- 如果当前节点 `node` 为 `None`,则说明 `p`、`q` 不在 `node` 的子树中,不可能为公共祖先,直接返回 `None`。 +- 如果当前节点 `node` 等于 `p` 或者 `q`,那么 `node` 就是 `p`、`q` 的最近公共祖先,直接返回 `node`。 +- 递归遍历左子树、右子树,并判断左右子树结果。 + - 如果左子树为空,则返回右子树。 + - 如果右子树为空,则返回左子树。 + - 如果左右子树都不为空,则说明 `p`、`q` 在当前根节点的两侧,当前根节点就是他们的最近公共祖先。 + - 如果左右子树都为空,则返回空。 + +## 代码 + +```python +class Solution: + def lowestCommonAncestor(self, root: TreeNode, p: TreeNode, q: TreeNode) -> TreeNode: + if root == p or root == q: + return root + + if root: + node_left = self.lowestCommonAncestor(root.left, p, q) + node_right = self.lowestCommonAncestor(root.right, p, q) + if node_left and node_right: + return root + elif not node_left: + return node_right + else: + return node_left + return None +``` + diff --git a/docs/solutions/interviews/group-anagrams-lcci.md b/docs/solutions/interviews/group-anagrams-lcci.md new file mode 100644 index 00000000..ccde9231 --- /dev/null +++ b/docs/solutions/interviews/group-anagrams-lcci.md @@ -0,0 +1,42 @@ +# [面试题 10.02. 变位词组](https://leetcode.cn/problems/group-anagrams-lcci/) + +- 标签:数组、哈希表、字符串、排序 +- 难度:中等 + +## 题目链接 + +- [面试题 10.02. 变位词组 - 力扣](https://leetcode.cn/problems/group-anagrams-lcci/) + +## 题目大意 + +给定一个字符串数组 `strs`。 + +要求:将所有变位词组合在一起。不需要考虑输出顺序。 + +- 变位词:字母相同,但排列不同的字符串。 + +## 解题思路 + +使用哈希表记录变位词。对每一个字符串进行排序,按照 `排序字符串:变位词数组` 的键值顺序进行存储。 + +最终将哈希表的值转换为对应数组返回结果。 + +## 代码 + +```python +class Solution: + def groupAnagrams(self, strs: List[str]) -> List[List[str]]: + str_dict = dict() + res = [] + for s in strs: + sort_s = str(sorted(s)) + if sort_s in str_dict: + str_dict[sort_s] += [s] + else: + str_dict[sort_s] = [s] + + for sort_s in str_dict: + res += [str_dict[sort_s]] + return res +``` + diff --git a/docs/solutions/interviews/implement-queue-using-stacks-lcci.md b/docs/solutions/interviews/implement-queue-using-stacks-lcci.md new file mode 100644 index 00000000..64993a2f --- /dev/null +++ b/docs/solutions/interviews/implement-queue-using-stacks-lcci.md @@ -0,0 +1,74 @@ +# [面试题 03.04. 化栈为队](https://leetcode.cn/problems/implement-queue-using-stacks-lcci/) + +- 标签:栈、设计、队列 +- 难度:简单 + +## 题目链接 + +- [面试题 03.04. 化栈为队 - 力扣](https://leetcode.cn/problems/implement-queue-using-stacks-lcci/) + +## 题目大意 + +要求:实现一个 MyQueue 类,要求仅使用两个栈实现先入先出队列。 + +## 解题思路 + +使用两个栈,`inStack` 用于输入,`outStack` 用于输出。 + +- `push` 操作:将元素压入 `inStack` 中。 +- `pop` 操作:如果 `outStack` 输出栈为空,将 `inStack` 输入栈元素依次取出,按顺序压入 `outStack` 栈。这样 `outStack` 栈的元素顺序和之前 `inStack` 元素顺序相反,`outStack` 顶层元素就是要取出的队头元素,将其移出,并返回该元素。如果 `outStack` 输出栈不为空,则直接取出顶层元素。 +- `peek` 操作:和 `pop` 操作类似,只不过最后一步不需要取出顶层元素,直接将其返回即可。 +- `empty` 操作:如果 `inStack` 和 `outStack` 都为空,则队列为空,否则队列不为空。 + +## 代码 + +```python +class MyQueue: + + def __init__(self): + """ + Initialize your data structure here. + """ + self.inStack = [] + self.outStack = [] + + + def push(self, x: int) -> None: + """ + Push element x to the back of queue. + """ + self.inStack.append(x) + + + def pop(self) -> int: + """ + Removes the element from in front of queue and returns that element. + """ + if (len(self.outStack) == 0): + while (len(self.inStack) != 0): + self.outStack.append(self.inStack[-1]) + self.inStack.pop() + top = self.outStack[-1] + self.outStack.pop() + return top + + + def peek(self) -> int: + """ + Get the front element. + """ + if (len(self.outStack) == 0): + while (len(self.inStack) != 0): + self.outStack.append(self.inStack[-1]) + self.inStack.pop() + top = self.outStack[-1] + return top + + + def empty(self) -> bool: + """ + Returns whether the queue is empty. + """ + return len(self.outStack) == 0 and len(self.inStack) == 0 +``` + diff --git a/docs/solutions/interviews/index.md b/docs/solutions/interviews/index.md new file mode 100644 index 00000000..3410fb8b --- /dev/null +++ b/docs/solutions/interviews/index.md @@ -0,0 +1,32 @@ +## 本章内容 + +- [面试题 01.07. 旋转矩阵](https://github.com/ITCharge/AlgoNote/tree/main/docs/solutions/interviews/rotate-matrix-lcci.md) +- [面试题 01.08. 零矩阵](https://github.com/ITCharge/AlgoNote/tree/main/docs/solutions/interviews/zero-matrix-lcci.md) +- [面试题 02.02. 返回倒数第 k 个节点](https://github.com/ITCharge/AlgoNote/tree/main/docs/solutions/interviews/kth-node-from-end-of-list-lcci.md) +- [面试题 02.05. 链表求和](https://github.com/ITCharge/AlgoNote/tree/main/docs/solutions/interviews/sum-lists-lcci.md) +- [面试题 02.06. 回文链表](https://github.com/ITCharge/AlgoNote/tree/main/docs/solutions/interviews/palindrome-linked-list-lcci.md) +- [面试题 02.07. 链表相交](https://github.com/ITCharge/AlgoNote/tree/main/docs/solutions/interviews/intersection-of-two-linked-lists-lcci.md) +- [面试题 02.08. 环路检测](https://github.com/ITCharge/AlgoNote/tree/main/docs/solutions/interviews/linked-list-cycle-lcci.md) +- [面试题 03.02. 栈的最小值](https://github.com/ITCharge/AlgoNote/tree/main/docs/solutions/interviews/min-stack-lcci.md) +- [面试题 03.04. 化栈为队](https://github.com/ITCharge/AlgoNote/tree/main/docs/solutions/interviews/implement-queue-using-stacks-lcci.md) +- [面试题 04.02. 最小高度树](https://github.com/ITCharge/AlgoNote/tree/main/docs/solutions/interviews/minimum-height-tree-lcci.md) +- [面试题 04.05. 合法二叉搜索树](https://github.com/ITCharge/AlgoNote/tree/main/docs/solutions/interviews/legal-binary-search-tree-lcci.md) +- [面试题 04.06. 后继者](https://github.com/ITCharge/AlgoNote/tree/main/docs/solutions/interviews/successor-lcci.md) +- [面试题 04.08. 首个共同祖先](https://github.com/ITCharge/AlgoNote/tree/main/docs/solutions/interviews/first-common-ancestor-lcci.md) +- [面试题 04.12. 求和路径](https://github.com/ITCharge/AlgoNote/tree/main/docs/solutions/interviews/paths-with-sum-lcci.md) +- [面试题 08.04. 幂集](https://github.com/ITCharge/AlgoNote/tree/main/docs/solutions/interviews/power-set-lcci.md) +- [面试题 08.07. 无重复字符串的排列组合](https://github.com/ITCharge/AlgoNote/tree/main/docs/solutions/interviews/permutation-i-lcci.md) +- [面试题 08.08. 有重复字符串的排列组合](https://github.com/ITCharge/AlgoNote/tree/main/docs/solutions/interviews/permutation-ii-lcci.md) +- [面试题 08.09. 括号](https://github.com/ITCharge/AlgoNote/tree/main/docs/solutions/interviews/bracket-lcci.md) +- [面试题 08.10. 颜色填充](https://github.com/ITCharge/AlgoNote/tree/main/docs/solutions/interviews/color-fill-lcci.md) +- [面试题 08.12. 八皇后](https://github.com/ITCharge/AlgoNote/tree/main/docs/solutions/interviews/eight-queens-lcci.md) +- [面试题 10.01. 合并排序的数组](https://github.com/ITCharge/AlgoNote/tree/main/docs/solutions/interviews/sorted-merge-lcci.md) +- [面试题 10.02. 变位词组](https://github.com/ITCharge/AlgoNote/tree/main/docs/solutions/interviews/group-anagrams-lcci.md) +- [面试题 10.09. 排序矩阵查找](https://github.com/ITCharge/AlgoNote/tree/main/docs/solutions/interviews/sorted-matrix-search-lcci.md) +- [面试题 16.02. 单词频率](https://github.com/ITCharge/AlgoNote/tree/main/docs/solutions/interviews/words-frequency-lcci.md) +- [面试题 16.05. 阶乘尾数](https://github.com/ITCharge/AlgoNote/tree/main/docs/solutions/interviews/factorial-zeros-lcci.md) +- [面试题 16.26. 计算器](https://github.com/ITCharge/AlgoNote/tree/main/docs/solutions/interviews/calculator-lcci.md) +- [面试题 17.06. 2出现的次数](https://github.com/ITCharge/AlgoNote/tree/main/docs/solutions/interviews/number-of-2s-in-range-lcci.md) +- [面试题 17.14. 最小K个数](https://github.com/ITCharge/AlgoNote/tree/main/docs/solutions/interviews/smallest-k-lcci.md) +- [面试题 17.15. 最长单词](https://github.com/ITCharge/AlgoNote/tree/main/docs/solutions/interviews/longest-word-lcci.md) +- [面试题 17.17. 多次搜索](https://github.com/ITCharge/AlgoNote/tree/main/docs/solutions/interviews/multi-search-lcci.md) diff --git a/docs/solutions/interviews/intersection-of-two-linked-lists-lcci.md b/docs/solutions/interviews/intersection-of-two-linked-lists-lcci.md new file mode 100644 index 00000000..a985f070 --- /dev/null +++ b/docs/solutions/interviews/intersection-of-two-linked-lists-lcci.md @@ -0,0 +1,54 @@ +# [面试题 02.07. 链表相交](https://leetcode.cn/problems/intersection-of-two-linked-lists-lcci/) + +- 标签:哈希表、链表、双指针 +- 难度:简单 + +## 题目链接 + +- [面试题 02.07. 链表相交 - 力扣](https://leetcode.cn/problems/intersection-of-two-linked-lists-lcci/) + +## 题目大意 + +给定两个链表的头节点 `headA`、`headB`。 + +要求:找出并返回两个单链表相交的起始节点。如果两个链表没有交点,返回 `None` 。 + +比如:链表 A 为 `[4, 1, 8, 4, 5]`,链表 B 为 `[5, 0, 1, 8, 4, 5]`。则如下图所示,两个链表相交的起始节点为 `8`,则输出结果为 `8`。 + +![](https://assets.leetcode.com/uploads/2018/12/13/160_example_1.png) + + + + + +## 解题思路 + +如果两个链表相交,那么从相交位置开始,到结束,必有一段等长且相同的节点。假设链表 `A` 的长度为 `m`、链表 `B` 的长度为 `n`,他们的相交序列有 `k` 个,则相交情况可以如下如所示: + +![](https://qcdn.itcharge.cn/images/20210401113538.png) + +现在问题是如何找到 `m - k` 或者 `n - k` 的位置。 + +考虑将链表 `A` 的末尾拼接上链表 `B`,链表 `B` 的末尾拼接上链表 `A`。 + +然后使用两个指针 `pA` 、`pB`,分别从链表 `A`、链表 `B` 的头节点开始遍历,如果走到共同的节点,则返回该节点。 + +否则走到两个链表末尾,返回 `None`。 + +![](https://qcdn.itcharge.cn/images/20210401114100.png) + +## 代码 + +```python +class Solution: + def getIntersectionNode(self, headA: ListNode, headB: ListNode) -> ListNode: + if headA == None or headB == None: + return None + pA = headA + pB = headB + while pA != pB : + pA = pA.next if pA != None else headB + pB = pB.next if pB != None else headA + return pA +``` + diff --git a/docs/solutions/interviews/kth-node-from-end-of-list-lcci.md b/docs/solutions/interviews/kth-node-from-end-of-list-lcci.md new file mode 100644 index 00000000..adec3b65 --- /dev/null +++ b/docs/solutions/interviews/kth-node-from-end-of-list-lcci.md @@ -0,0 +1,38 @@ +# [面试题 02.02. 返回倒数第 k 个节点](https://leetcode.cn/problems/kth-node-from-end-of-list-lcci/) + +- 标签:链表、双指针 +- 难度:简单 + +## 题目链接 + +- [面试题 02.02. 返回倒数第 k 个节点 - 力扣](https://leetcode.cn/problems/kth-node-from-end-of-list-lcci/) + +## 题目大意 + +给定一个链表的头节点 `head`,以及一个整数 `k`。 + +要求:返回链表的倒数第 `k` 个节点的值。 + +## 解题思路 + +常规思路是遍历一遍链表,求出链表长度,再遍历一遍到对应位置,返回该位置上的节点。 + +如果用一次遍历实现的话,可以使用快慢指针。让快指针先走 `k` 步,然后快慢指针、慢指针再同时走,每次一步,这样等快指针遍历到链表尾部的时候,慢指针就刚好遍历到了倒数第 `k` 个节点位置。返回该该位置上的节点即可。 + +## 代码 + +```python +class Solution: + def kthToLast(self, head: ListNode, k: int) -> int: + slow = head + fast = head + for _ in range(k): + if fast == None: + return fast + fast = fast.next + while fast: + slow = slow.next + fast = fast.next + return slow.val +``` + diff --git a/docs/solutions/interviews/legal-binary-search-tree-lcci.md b/docs/solutions/interviews/legal-binary-search-tree-lcci.md new file mode 100644 index 00000000..d78f5baf --- /dev/null +++ b/docs/solutions/interviews/legal-binary-search-tree-lcci.md @@ -0,0 +1,46 @@ +# [面试题 04.05. 合法二叉搜索树](https://leetcode.cn/problems/legal-binary-search-tree-lcci/) + +- 标签:树、深度优先搜索、二叉搜索树、二叉树 +- 难度:中等 + +## 题目链接 + +- [面试题 04.05. 合法二叉搜索树 - 力扣](https://leetcode.cn/problems/legal-binary-search-tree-lcci/) + +## 题目大意 + +给定一个二叉树的根节点 `root`。 + +要求:检查该二叉树是否为二叉搜索树。 + +二叉搜索树特征: + +- 节点的左子树只包含小于当前节点的数。 +- 节点的右子树只包含大于当前节点的数。 +- 所有左子树和右子树自身必须也是二叉搜索树。 + +## 解题思路 + +根据题意进行递归遍历即可。前序、中序、后序遍历都可以。 + +以前序遍历为例,递归函数为:`preorderTraversal(root, min_v, max_v)` + +前序遍历时,先判断根节点的值是否在 `(min_v, max_v)` 之间。如果不在则直接返回 `False`。在区间内,则继续递归检测左右子树是否满足,都满足才是一棵二叉搜索树。 + +递归遍历左子树的时候,要将上界 `max_v` 改为左子树的根节点值,因为左子树上所有节点的值均小于根节点的值。同理,遍历右子树的时候,要将下界 `min_v` 改为右子树的根节点值,因为右子树上所有节点的值均大于根节点。 + +## 代码 + +```python +class Solution: + def isValidBST(self, root: TreeNode) -> bool: + def preorderTraversal(root, min_v, max_v): + if root == None: + return True + if root.val >= max_v or root.val <= min_v: + return False + return preorderTraversal(root.left, min_v, root.val) and preorderTraversal(root.right, root.val, max_v) + + return preorderTraversal(root, float('-inf'), float('inf')) +``` + diff --git a/docs/solutions/interviews/linked-list-cycle-lcci.md b/docs/solutions/interviews/linked-list-cycle-lcci.md new file mode 100644 index 00000000..bc98e81f --- /dev/null +++ b/docs/solutions/interviews/linked-list-cycle-lcci.md @@ -0,0 +1,47 @@ +# [面试题 02.08. 环路检测](https://leetcode.cn/problems/linked-list-cycle-lcci/) + +- 标签:哈希表、链表、双指针 +- 难度:中等 + +## 题目链接 + +- [面试题 02.08. 环路检测 - 力扣](https://leetcode.cn/problems/linked-list-cycle-lcci/) + +## 题目大意 + +给定一个链表的头节点 `head`。 + +要求:判断链表中是否有环,如果有环则返回入环的第一个节点,无环则返回 None。 + +## 解题思路 + +利用两个指针,一个慢指针每次前进一步,快指针每次前进两步(两步或多步效果是等价的)。如果两个指针在链表头节点以外的某一节点相遇(即相等)了,那么说明链表有环,否则,如果(快指针)到达了某个没有后继指针的节点时,那么说明没环。 + +如果有环,则再定义一个指针,和慢指针一起每次移动一步,两个指针相遇的位置即为入口节点。 + +这是因为:假设入环位置为 A,快慢指针在在 B 点相遇,则相遇时慢指针走了 $a + b$ 步,快指针走了 $a + n(b+c) + b$ 步。 + +$2(a + b) = a + n(b + c) + b$。可以推出:$a = c + (n-1)(b + c)$。 + +我们可以发现:从相遇点到入环点的距离 $c$ 加上 $n-1$ 圈的环长 $b + c$ 刚好等于从链表头部到入环点的距离。 + +## 代码 + +```python +class Solution: + def detectCycle(self, head: ListNode) -> ListNode: + fast, slow = head, head + while True: + if not fast or not fast.next: + return None + fast = fast.next.next + slow = slow.next + if fast == slow: + break + + ans = head + while ans != slow: + ans, slow = ans.next, slow.next + return ans +``` + diff --git a/docs/solutions/interviews/longest-word-lcci.md b/docs/solutions/interviews/longest-word-lcci.md new file mode 100644 index 00000000..015aab7e --- /dev/null +++ b/docs/solutions/interviews/longest-word-lcci.md @@ -0,0 +1,95 @@ +# [面试题 17.15. 最长单词](https://leetcode.cn/problems/longest-word-lcci/) + +- 标签:字典树、数组、哈希表、字符串 +- 难度:中等 + +## 题目链接 + +- [面试题 17.15. 最长单词 - 力扣](https://leetcode.cn/problems/longest-word-lcci/) + +## 题目大意 + +给定一组单词 `words`。 + +要求:找出其中的最长单词,且该单词由这组单词中的其他单词组合而成。若有多个长度相同的结果,返回其中字典序最小的一项,若没有符合要求的单词则返回空字符串。 + +## 解题思路 + +先将所有单词按照长度从长到短排序,相同长度的字典序小的排在前面。然后将所有单词存入字典树中。 + +然后一重循环遍历所有单词 `word`,二重循环遍历单词中所有字符 `word[i]`。 + +如果当前遍历的字符为单词末尾,递归判断从 `i + 1` 位置开始,剩余部分是否可以切分为其他单词组合,如果可以切分,则返回当前单词 `word`。如果不可以切分,则返回空字符串 `""`。 + +## 代码 + +```python +class Trie: + + def __init__(self): + """ + Initialize your data structure here. + """ + self.children = dict() + self.isEnd = False + + + def insert(self, word: str) -> None: + """ + Inserts a word into the trie. + """ + cur = self + for ch in word: + if ch not in cur.children: + cur.children[ch] = Trie() + cur = cur.children[ch] + cur.isEnd = True + + + def search(self, word: str) -> bool: + """ + Returns if the word is in the trie. + """ + cur = self + for ch in word: + if ch not in cur.children: + return False + cur = cur.children[ch] + + return cur is not None and cur.isEnd + + def splitToWord(self, remain): + if not remain or remain == "": + return True + cur = self + for i in range(len(remain)): + ch = remain[i] + if ch not in cur.children: + return False + if cur.children[ch].isEnd and self.splitToWord(remain[i + 1:]): + return True + cur = cur.children[ch] + return False + + def dfs(self, words): + for word in words: + cur = self + size = len(word) + for i in range(size): + ch = word[i] + if i < size - 1 and cur.children[ch].isEnd and self.splitToWord(word[i+1:]): + return word + cur = cur.children[ch] + return "" + +class Solution: + def longestWord(self, words: List[str]) -> str: + words.sort(key=lambda x: (-len(x), x)) + trie_tree = Trie() + for word in words: + trie_tree.insert(word) + + ans = trie_tree.dfs(words) + return ans +``` + diff --git a/docs/solutions/interviews/min-stack-lcci.md b/docs/solutions/interviews/min-stack-lcci.md new file mode 100644 index 00000000..44a538ff --- /dev/null +++ b/docs/solutions/interviews/min-stack-lcci.md @@ -0,0 +1,59 @@ +# [面试题 03.02. 栈的最小值](https://leetcode.cn/problems/min-stack-lcci/) + +- 标签:栈、设计 +- 难度:简单 + +## 题目链接 + +- [面试题 03.02. 栈的最小值 - 力扣](https://leetcode.cn/problems/min-stack-lcci/) + +## 题目大意 + +设计一个「栈」,要求实现 `push` ,`pop` ,`top` ,`getMin` 操作,其中 `getMin` 要求能在常数时间内实现。 + +## 解题思路 + +使用一个栈,栈元素中除了保存当前值之外,再保存一个当前最小值。 + +- `push` 操作:如果栈不为空,则判断当前值与栈顶元素所保存的最小值,并更新当前最小值,将新元素保存到栈中。 +- `pop`操作:正常出栈 +- `top` 操作:返回栈顶元素保存的值。 +- `getMin` 操作:返回栈顶元素保存的最小值。 + +## 代码 + +```python +class MinStack: + + def __init__(self): + """ + initialize your data structure here. + """ + self.stack = [] + + class Node: + def __init__(self, x): + self.val = x + self.min = x + + def push(self, x: int) -> None: + node = self.Node(x) + if len(self.stack) == 0: + self.stack.append(node) + else: + topNode = self.stack[-1] + if node.min > topNode.min: + node.min = topNode.min + + self.stack.append(node) + + def pop(self) -> None: + self.stack.pop() + + def top(self) -> int: + return self.stack[-1].val + + def getMin(self) -> int: + return self.stack[-1].min +``` + diff --git a/docs/solutions/interviews/minimum-height-tree-lcci.md b/docs/solutions/interviews/minimum-height-tree-lcci.md new file mode 100644 index 00000000..7b22bf8f --- /dev/null +++ b/docs/solutions/interviews/minimum-height-tree-lcci.md @@ -0,0 +1,34 @@ +# [面试题 04.02. 最小高度树](https://leetcode.cn/problems/minimum-height-tree-lcci/) + +- 标签:树、二叉搜索树、数组、分治、二叉树 +- 难度:简单 + +## 题目链接 + +- [面试题 04.02. 最小高度树 - 力扣](https://leetcode.cn/problems/minimum-height-tree-lcci/) + +## 题目大意 + +给定一个升序的有序数组 `nums`。 + +要求:创建一棵高度最小的二叉搜索树(高度平衡的二叉搜索树)。 + +## 解题思路 + +直观上,如果把数组的中间元素当做根,那么数组左侧元素都小于根节点,右侧元素都大于根节点,且左右两侧元素个数相同,或最多相差 `1` 个。那么构建的树高度差也不会超过 `1`。所以猜想出:如果左右子树约平均,树就越平衡。这样我们就可以每次取中间元素作为当前的根节点,两侧的元素作为左右子树递归建树,左侧区间 `[L, mid - 1]` 作为左子树,右侧区间 `[mid + 1, R]` 作为右子树。 + +## 代码 + +```python +class Solution: + def sortedArrayToBST(self, nums: List[int]) -> TreeNode: + size = len(nums) + if size == 0: + return None + mid = size // 2 + root = TreeNode(nums[mid]) + root.left = Solution.sortedArrayToBST(self, nums[:mid]) + root.right = Solution.sortedArrayToBST(self, nums[mid + 1:]) + return root +``` + diff --git a/docs/solutions/interviews/multi-search-lcci.md b/docs/solutions/interviews/multi-search-lcci.md new file mode 100644 index 00000000..12891e29 --- /dev/null +++ b/docs/solutions/interviews/multi-search-lcci.md @@ -0,0 +1,80 @@ +# [面试题 17.17. 多次搜索](https://leetcode.cn/problems/multi-search-lcci/) + +- 标签:字典树、数组、哈希表、字符串、字符串匹配、滑动窗口 +- 难度:中等 + +## 题目链接 + +- [面试题 17.17. 多次搜索 - 力扣](https://leetcode.cn/problems/multi-search-lcci/) + +## 题目大意 + +给定一个较长字符串 `big` 和一个包含较短字符串的数组 `smalls`。 + +要求:设计一个方法,根据 `smalls` 中的每一个较短字符串,对 `big` 进行搜索。输出 `smalls` 中的字符串在 `big` 里出现的所有位置 `positions`,其中 `positions[i]` 为 `smalls[i]` 出现的所有位置。 + +## 解题思路 + +构建字典树,将 `smalls` 中所有字符串存入字典树中,并在字典树中记录下插入字符串的顺序下标。 + +然后一重循环遍历 `big`,表示从第 `i` 位置开始的字符串 `big[i:]`。然后在字符串前缀中搜索对应的单词,将所有符合要求的单词插入顺序位置存入列表中,返回列表。 + +对于列表中每个单词插入下标顺序 `index` 和 `big[i:]` 来说, `i` 就是 `smalls` 中第 `index` 个字符串所对应在 `big` 中的开始位置,将其存入答案数组并返回即可。 + +## 代码 + +```python +class Trie: + + def __init__(self): + """ + Initialize your data structure here. + """ + self.children = dict() + self.isEnd = False + self.index = -1 + + + def insert(self, word: str, index: int) -> None: + """ + Inserts a word into the trie. + """ + cur = self + for ch in word: + if ch not in cur.children: + cur.children[ch] = Trie() + cur = cur.children[ch] + cur.isEnd = True + cur.index = index + + + def search(self, text: str) -> list: + """ + Returns if the word is in the trie. + """ + cur = self + res = [] + for i in range(len(text)): + ch = text[i] + if ch not in cur.children: + return res + cur = cur.children[ch] + if cur.isEnd: + res.append(cur.index) + return res + +class Solution: + def multiSearch(self, big: str, smalls: List[str]) -> List[List[int]]: + trie_tree = Trie() + for i in range(len(smalls)): + word = smalls[i] + trie_tree.insert(word, i) + + res = [[] for _ in range(len(smalls))] + + for i in range(len(big)): + for index in trie_tree.search(big[i:]): + res[index].append(i) + return res +``` + diff --git a/docs/solutions/interviews/number-of-2s-in-range-lcci.md b/docs/solutions/interviews/number-of-2s-in-range-lcci.md new file mode 100644 index 00000000..3fe09ff1 --- /dev/null +++ b/docs/solutions/interviews/number-of-2s-in-range-lcci.md @@ -0,0 +1,85 @@ +# [面试题 17.06. 2出现的次数](https://leetcode.cn/problems/number-of-2s-in-range-lcci/) + +- 标签:递归、数学、动态规划 +- 难度:困难 + +## 题目链接 + +- [面试题 17.06. 2出现的次数 - 力扣](https://leetcode.cn/problems/number-of-2s-in-range-lcci/) + +## 题目大意 + +**描述**:给定一个整数 $n$。 + +**要求**:计算从 $0$ 到 $n$ (包含 $n$) 中数字 $2$ 出现的次数。 + +**说明**: + +- $n \le 10^9$。 + +**示例**: + +- 示例 1: + +```python +输入: 25 +输出: 9 +解释: (2, 12, 20, 21, 22, 23, 24, 25)(注意 22 应该算作两次) +``` + +## 解题思路 + +### 思路 1:动态规划 + 数位 DP + +将 $n$ 转换为字符串 $s$,定义递归函数 `def dfs(pos, cnt, isLimit):` 表示构造第 $pos$ 位及之后所有数位中数字 $2$ 出现的个数。接下来按照如下步骤进行递归。 + +1. 从 `dfs(0, 0, True)` 开始递归。 `dfs(0, 0, True)` 表示: + 1. 从位置 $0$ 开始构造。 + 2. 初始数字 $2$ 出现的个数为 $0$。 + 3. 开始时受到数字 $n$ 对应最高位数位的约束。 +2. 如果遇到 $pos == len(s)$,表示到达数位末尾,此时:返回数字 $2$ 出现的个数 $cnt$。 +3. 如果 $pos \ne len(s)$,则定义方案数 $ans$,令其等于 $0$,即:`ans = 0`。 +4. 如果遇到 $isNum == False$,说明之前位数没有填写数字,当前位可以跳过,这种情况下方案数等于 $pos + 1$ 位置上没有受到 $pos$ 位的约束,并且之前没有填写数字时的方案数,即:`ans = dfs(i + 1, state, False, False)`。 +5. 如果 $isNum == True$,则当前位必须填写一个数字。此时: + 1. 因为不需要考虑前导 $0$ 所以当前位数位所能选择的最小数字($minX$)为 $0$。 + 2. 根据 $isLimit$ 来决定填当前位数位所能选择的最大数字($maxX$)。 + 3. 然后根据 $[minX, maxX]$ 来枚举能够填入的数字 $d$。 + 4. 方案数累加上当前位选择 $d$ 之后的方案数,即:`ans += dfs(pos + 1, cnt + (d == 2), isLimit and d == maxX)`。 + 1. `cnt + (d == 2)` 表示之前数字 $2$ 出现的个数加上当前位为数字 $2$ 的个数。 + 2. `isLimit and d == maxX` 表示 $pos + 1$ 位受到之前位 $pos$ 位限制。 +6. 最后的方案数为 `dfs(0, 0, True)`,将其返回即可。 + +### 思路 1:代码 + +```python +class Solution: + def numberOf2sInRange(self, n: int) -> int: + # 将 n 转换为字符串 s + s = str(n) + + @cache + # pos: 第 pos 个数位 + # cnt: 之前数字 2 出现的个数。 + # isLimit: 表示是否受到选择限制。如果为真,则第 pos 位填入数字最多为 s[pos];如果为假,则最大可为 9。 + def dfs(pos, cnt, isLimit): + if pos == len(s): + return cnt + + ans = 0 + # 不需要考虑前导 0,则最小可选择数字为 0 + minX = 0 + # 如果受到选择限制,则最大可选择数字为 s[pos],否则最大可选择数字为 9。 + maxX = int(s[pos]) if isLimit else 9 + + # 枚举可选择的数字 + for d in range(minX, maxX + 1): + ans += dfs(pos + 1, cnt + (d == 2), isLimit and d == maxX) + return ans + + return dfs(0, 0, True) +``` + +### 思路 1:复杂度分析 + +- **时间复杂度**:$O(\log n)$。 +- **空间复杂度**:$O(\log n)$。 diff --git a/docs/solutions/interviews/palindrome-linked-list-lcci.md b/docs/solutions/interviews/palindrome-linked-list-lcci.md new file mode 100644 index 00000000..9907bb09 --- /dev/null +++ b/docs/solutions/interviews/palindrome-linked-list-lcci.md @@ -0,0 +1,32 @@ +# [面试题 02.06. 回文链表](https://leetcode.cn/problems/palindrome-linked-list-lcci/) + +- 标签:栈、递归、链表、双指针 +- 难度:简单 + +## 题目链接 + +- [面试题 02.06. 回文链表 - 力扣](https://leetcode.cn/problems/palindrome-linked-list-lcci/) + +## 题目大意 + +给定一个链表的头节点 `head`。 + +要求:判断该链表是否为回文链表。 + +## 解题思路 + +利用数组,将链表元素依次存入。然后再使用两个指针,一个指向数组开始位置,一个指向数组结束位置,依次判断首尾对应元素是否相等,若都相等,则为回文链表。若不相等,则不是回文链表。 + +## 代码 + +```python +class Solution: + def isPalindrome(self, head: ListNode) -> bool: + nodes = [] + p1 = head + while p1 != None: + nodes.append(p1.val) + p1 = p1.next + return nodes == nodes[::-1] +``` + diff --git a/docs/solutions/interviews/paths-with-sum-lcci.md b/docs/solutions/interviews/paths-with-sum-lcci.md new file mode 100644 index 00000000..0cec25c8 --- /dev/null +++ b/docs/solutions/interviews/paths-with-sum-lcci.md @@ -0,0 +1,45 @@ +# [面试题 04.12. 求和路径](https://leetcode.cn/problems/paths-with-sum-lcci/) + +- 标签:树、深度优先搜索、二叉树 +- 难度:中等 + +## 题目链接 + +- [面试题 04.12. 求和路径 - 力扣](https://leetcode.cn/problems/paths-with-sum-lcci/) + +## 题目大意 + +给定一个二叉树的根节点 `root`,和一个整数 `targetSum`。 + +要求:求出该二叉树里节点值之和等于 `targetSum` 的路径的数目。 + +- 路径:不需要从根节点开始,也不需要在叶子节点结束,但是路径方向必须是向下的(只能从父节点到子节点)。 + +## 解题思路 + +直观想法是: + +以每一个节点 `node` 为起始节点,向下检测延伸的路径。递归遍历每一个节点所有可能的路径,然后将这些路径数目加起来即为答案。 + +但是这样会存在许多重复计算。我们可以定义节点的前缀和来减少重复计算。 + +- 节点的前缀和:从根节点到当前节点路径上所有节点的和。 + +有了节点的前缀和,我们就可以通过前缀和来计算两节点之间的路劲和。即:`则两节点之间的路径和 = 两节点之间的前缀和之差`。 + +为了计算符合要求的路径数量,我们用哈希表存储「前缀和的节点数量」。哈希表以「当前节点的前缀和」为键,以「该前缀和的节点数量」为值。这样就能通过哈希表直接计算出符合要求的路径数量,从而累加到答案上。 + +整个算法的具体步骤如下: + +- 通过先序遍历方式递归遍历二叉树,计算每一个节点的前缀和 `cur_sum`。 +- 从哈希表中取出 `cur_sum - target_sum` 的路径数量(也就是表示存在从前缀和为 `cur_sum - target_sum` 所对应的节点到前缀和为 `cur_sum` 所对应的节点的路径个数)累加到答案 `res` 中。 +- 然后以「当前节点的前缀和」为键,以「该前缀和的节点数量」为值,存入哈希表中。 +- 递归遍历二叉树,并累加答案值。 +- 恢复哈希表「当前前缀和的节点数量」,返回答案。 + +## 代码 + +```python + +``` + diff --git a/docs/solutions/interviews/permutation-i-lcci.md b/docs/solutions/interviews/permutation-i-lcci.md new file mode 100644 index 00000000..f5cd4488 --- /dev/null +++ b/docs/solutions/interviews/permutation-i-lcci.md @@ -0,0 +1,46 @@ +# [面试题 08.07. 无重复字符串的排列组合](https://leetcode.cn/problems/permutation-i-lcci/) + +- 标签:字符串、回溯 +- 难度:中等 + +## 题目链接 + +- [面试题 08.07. 无重复字符串的排列组合 - 力扣](https://leetcode.cn/problems/permutation-i-lcci/) + +## 题目大意 + +给定一个字符串 `S`。 + +要求:打印出该字符串中字符的所有排列。可以以任意顺序返回这个字符串数组,但里边不能有重复元素。 + +## 解题思路 + +使用 `visited` 数组标记该元素在当前排列中是否被访问过。若未被访问过则将其加入排列中,并在访问后将该元素变为未访问状态。然后进行回溯遍历。 + +## 代码 + +```python +class Solution: + res = [] + path = [] + + def backtrack(self, S, visited): + if len(self.path) == len(S): + self.res.append(''.join(self.path)) + return + for i in range(len(S)): + if not visited[i]: + visited[i] = True + self.path.append(S[i]) + self.backtrack(S, visited) + self.path.pop() + visited[i] = False + + def permutation(self, S: str) -> List[str]: + self.res.clear() + self.path.clear() + visited = [False for _ in range(len(S))] + self.backtrack(S, visited) + return self.res +``` + diff --git a/docs/solutions/interviews/permutation-ii-lcci.md b/docs/solutions/interviews/permutation-ii-lcci.md new file mode 100644 index 00000000..8f9edeb5 --- /dev/null +++ b/docs/solutions/interviews/permutation-ii-lcci.md @@ -0,0 +1,55 @@ +# [面试题 08.08. 有重复字符串的排列组合](https://leetcode.cn/problems/permutation-ii-lcci/) + +- 标签:字符串、回溯 +- 难度:中等 + +## 题目链接 + +- [面试题 08.08. 有重复字符串的排列组合 - 力扣](https://leetcode.cn/problems/permutation-ii-lcci/) + +## 题目大意 + +给定一个字符串 `s`,字符串中包含有重复字符。 + +要求:打印出该字符串中字符的所有排列。可以以任意顺序返回这个字符串数组。 + +## 解题思路 + +因为原字符串可能含有重复元素,所以在回溯的时候需要进行去重。先将字符串 `s` 转为 `list` 列表,再对列表进行排序,然后使用 `visited` 数组标记该元素在当前排列中是否被访问过。若未被访问过则将其加入排列中,并在访问后将该元素变为未访问状态。 + +然后再递归遍历下一层元素之前,增加一句语句进行判重:`if i > 0 and nums[i] == nums[i - 1] and not visited[i - 1]: continue`。 + +然后进行回溯遍历。 + +## 代码 + +```python +class Solution: + res = [] + path = [] + + def backtrack(self, ls, visited): + if len(self.path) == len(ls): + self.res.append(''.join(self.path)) + return + for i in range(len(ls)): + if i > 0 and ls[i] == ls[i - 1] and not visited[i - 1]: + continue + + if not visited[i]: + visited[i] = True + self.path.append(ls[i]) + self.backtrack(ls, visited) + self.path.pop() + visited[i] = False + + def permutation(self, S: str) -> List[str]: + self.res.clear() + self.path.clear() + ls = list(S) + ls.sort() + visited = [False for _ in range(len(S))] + self.backtrack(ls, visited) + return self.res +``` + diff --git a/docs/solutions/interviews/power-set-lcci.md b/docs/solutions/interviews/power-set-lcci.md new file mode 100644 index 00000000..b6f4d166 --- /dev/null +++ b/docs/solutions/interviews/power-set-lcci.md @@ -0,0 +1,35 @@ +# [面试题 08.04. 幂集](https://leetcode.cn/problems/power-set-lcci/) + +- 标签:位运算、数组、回溯 +- 难度:中等 + +## 题目链接 + +- [面试题 08.04. 幂集 - 力扣](https://leetcode.cn/problems/power-set-lcci/) + +## 题目大意 + +给定一个集合 `nums`,集合中不包含重复元素。 + +压枪欧秋:返回该集合的所有子集。 + +## 解题思路 + +回溯算法,遍历集合 `nums`。为了使得子集不重复,每次遍历从当前位置的下一个位置进行下一层遍历。 + +## 代码 + +```python +class Solution: + def subsets(self, nums: List[int]) -> List[List[int]]: + def backtrack(size, subset, index): + res.append(subset) + for i in range(index, size): + backtrack(size, subset + [nums[i]], i + 1) + + size = len(nums) + res = list() + backtrack(size, [], 0) + return res +``` + diff --git a/docs/solutions/interviews/rotate-matrix-lcci.md b/docs/solutions/interviews/rotate-matrix-lcci.md new file mode 100644 index 00000000..275cbe8f --- /dev/null +++ b/docs/solutions/interviews/rotate-matrix-lcci.md @@ -0,0 +1,67 @@ +# [面试题 01.07. 旋转矩阵](https://leetcode.cn/problems/rotate-matrix-lcci/) + +- 标签:数组、数学、矩阵 +- 难度:中等 + +## 题目链接 + +- [面试题 01.07. 旋转矩阵 - 力扣](https://leetcode.cn/problems/rotate-matrix-lcci/) + +## 题目大意 + +给定一个 `n * n` 大小的二维矩阵用来表示图像,其中每个像素的大小为 4 字节。 + +要求:设计一种算法,将图像旋转 90 度。并且要不占用额外内存空间。 + +## 解题思路 + +题目要求不占用额外内存空间,就是要在原二维矩阵上直接进行旋转操作。我们可以用翻转操作代替旋转操作。具体可以分为两步: + +1. 上下翻转。 + +2. 主对角线翻转。 + +举个例子: + +``` + 1 2 3 4 + 5 6 7 8 + 9 10 11 12 +13 14 15 16 +``` + +上下翻转后变为: + +``` +13 14 15 16 + 9 10 11 12 + 5 6 7 8 + 1 2 3 4 +``` + +在经过主对角线翻转后变为: + +``` +13 9 5 1 +14 10 6 2 +15 11 7 3 +16 12 8 4 +``` + +## 代码 + +```python +class Solution: + def rotate(self, matrix: List[List[int]]) -> None: + """ + Do not return anything, modify matrix in-place instead. + """ + size = len(matrix) + for i in range(size // 2): + for j in range(size): + matrix[i][j], matrix[size - i - 1][j] = matrix[size - i - 1][j], matrix[i][j] + for i in range(size): + for j in range(i): + matrix[i][j], matrix[j][i] = matrix[j][i], matrix[i][j] +``` + diff --git a/docs/solutions/interviews/smallest-k-lcci.md b/docs/solutions/interviews/smallest-k-lcci.md new file mode 100644 index 00000000..cc05a832 --- /dev/null +++ b/docs/solutions/interviews/smallest-k-lcci.md @@ -0,0 +1,73 @@ +# [面试题 17.14. 最小K个数](https://leetcode.cn/problems/smallest-k-lcci/) + +- 标签:数组、分治、快速选择、排序、堆(优先队列) +- 难度:中等 + +## 题目链接 + +- [面试题 17.14. 最小K个数 - 力扣](https://leetcode.cn/problems/smallest-k-lcci/) + +## 题目大意 + +给定整数数组 `arr`,再给定一个整数 `k`。 + +要求:返回数组 `arr` 中最小的 `k` 个数。 + +## 解题思路 + +直接可以想到的思路是:排序后输出数组上对应的最小的 k 个数。所以问题关键在于排序方法的复杂度。 + +冒泡排序、选择排序、插入排序时间复杂度 $O(n^2)$ 太高了,解答会超时。 + +可考虑堆排序、归并排序、快速排序。本题使用堆排序。具体做法如下: + +1. 利用数组前 `k` 个元素,建立大小为 `k` 的大顶堆。 +2. 遍历数组 `[k, size - 1]` 的元素,判断其与堆顶元素关系,如果比堆顶元素小,则将其赋值给堆顶元素,再对大顶堆进行调整。 +3. 最后输出前调整过后的大顶堆的前 `k` 个元素。 + +## 代码 + +```python +class Solution: + def heapify(self, nums: [int], index: int, end: int): + left = index * 2 + 1 + right = left + 1 + while left <= end: + # 当前节点为非叶子节点 + max_index = index + if nums[left] > nums[max_index]: + max_index = left + if right <= end and nums[right] > nums[max_index]: + max_index = right + if index == max_index: + # 如果不用交换,则说明已经交换结束 + break + nums[index], nums[max_index] = nums[max_index], nums[index] + # 继续调整子树 + index = max_index + left = index * 2 + 1 + right = left + 1 + + # 初始化大顶堆 + def buildMaxHeap(self, nums: [int], k: int): + # (k-2) // 2 是最后一个非叶节点,叶节点不用调整 + for i in range((k - 2) // 2, -1, -1): + self.heapify(nums, i, k - 1) + return nums + + def smallestK(self, arr: List[int], k: int) -> List[int]: + size = len(arr) + if k <= 0 or not arr: + return [] + if size <= k: + return arr + + self.buildMaxHeap(arr, k) + for i in range(k, size): + if arr[i] < arr[0]: + arr[i], arr[0] = arr[0], arr[i] + self.heapify(arr, 0, k - 1) + + return arr[:k] +``` + diff --git a/docs/solutions/interviews/sorted-matrix-search-lcci.md b/docs/solutions/interviews/sorted-matrix-search-lcci.md new file mode 100644 index 00000000..61c554e6 --- /dev/null +++ b/docs/solutions/interviews/sorted-matrix-search-lcci.md @@ -0,0 +1,90 @@ +# [面试题 10.09. 排序矩阵查找](https://leetcode.cn/problems/sorted-matrix-search-lcci/) + +- 标签:数组、二分查找、分治、矩阵 +- 难度:中等 + +## 题目链接 + +- [面试题 10.09. 排序矩阵查找 - 力扣](https://leetcode.cn/problems/sorted-matrix-search-lcci/) + +## 题目大意 + +给定一个 `m * n` 大小的有序整数矩阵。每一行、每一列都按升序排列。再给定一个目标值 `target`。 + +要求:判断矩阵中是否可以找到 `target`,若找到 `target`,返回 `True`,否则返回 `False`。 + +## 解题思路 + +矩阵是有序的,可以考虑使用二分搜索来进行查找。 + +迭代对角线元素,假设对角线元素的坐标为 `(row, col)`。把数组元素按对角线分为右上角部分和左下角部分。 + +则对于当前对角线元素右侧第 `row` 行、对角线元素下侧第 `col` 列进行二分查找。 + +- 如果找到目标,直接返回 `True`。 +- 如果找不到目标,则缩小范围,继续查找。 +- 直到所有对角线元素都遍历完,依旧没找到,则返回 `False`。 + +## 代码 + +```python +class Solution: + def diagonalBinarySearch(self, matrix, diagonal, target): + left = 0 + right = diagonal + while left < right: + mid = left + (right - left) // 2 + if matrix[mid][mid] < target: + left = mid + 1 + else: + right = mid + return left + + def rowBinarySearch(self, matrix, begin, cols, target): + left = begin + right = cols + while left < right: + mid = left + (right - left) // 2 + if matrix[begin][mid] < target: + left = mid + 1 + elif matrix[begin][mid] > target: + right = mid - 1 + else: + left = mid + break + return begin <= left <= cols and matrix[begin][left] == target + + def colBinarySearch(self, matrix, begin, rows, target): + left = begin + 1 + right = rows + while left < right: + mid = left + (right - left) // 2 + if matrix[mid][begin] < target: + left = mid + 1 + elif matrix[mid][begin] > target: + right = mid - 1 + else: + left = mid + break + return begin <= left <= rows and matrix[left][begin] == target + + def searchMatrix(self, matrix: List[List[int]], target: int) -> bool: + rows = len(matrix) + if rows == 0: + return False + cols = len(matrix[0]) + if cols == 0: + return False + + min_val = min(rows, cols) + index = self.diagonalBinarySearch(matrix, min_val - 1, target) + if matrix[index][index] == target: + return True + for i in range(index + 1): + row_search = self.rowBinarySearch(matrix, i, cols - 1, target) + col_search = self.colBinarySearch(matrix, i, rows - 1, target) + if row_search or col_search: + return True + return False +``` + diff --git a/docs/solutions/interviews/sorted-merge-lcci.md b/docs/solutions/interviews/sorted-merge-lcci.md new file mode 100644 index 00000000..ea05bd85 --- /dev/null +++ b/docs/solutions/interviews/sorted-merge-lcci.md @@ -0,0 +1,72 @@ +# [面试题 10.01. 合并排序的数组](https://leetcode.cn/problems/sorted-merge-lcci/) + +- 标签:数组、双指针、排序 +- 难度:简单 + +## 题目链接 + +- [面试题 10.01. 合并排序的数组 - 力扣](https://leetcode.cn/problems/sorted-merge-lcci/) + +## 题目大意 + +**描述**:给定两个排序后的数组 `A` 和 `B`,以及 `A` 的元素数量 `m` 和 `B` 的元素数量 `n`。 `A` 的末端有足够的缓冲空间容纳 `B`。 + +**要求**:编写一个方法,将 `B` 合并入 `A` 并排序。 + +**说明**: + +- $A.length == n + m$。 + +**示例**: + +- 示例 1: + +```python +输入: +A = [1,2,3,0,0,0], m = 3 +B = [2,5,6], n = 3 + +输出: [1,2,2,3,5,6] +``` + +## 解题思路 + +### 思路 1:归并排序 + +可以利用归并排序算法的归并步骤思路。 + +1. 使用两个指针分别表示`A`、`B` 正在处理的元素下标。 +2. 对 `A`、`B` 进行归并操作,将结果存入新数组中。归并之后,再将所有元素赋值到数组 `A` 中。 + +### 思路 1:代码 + +```python +class Solution: + def merge(self, A: List[int], m: int, B: List[int], n: int) -> None: + """ + Do not return anything, modify A in-place instead. + """ + arr = [] + index_A, index_B = 0, 0 + while index_A < m and index_B < n: + if A[index_A] <= B[index_B]: + arr.append(A[index_A]) + index_A += 1 + else: + arr.append(B[index_B]) + index_B += 1 + while index_A < m: + arr.append(A[index_A]) + index_A += 1 + while index_B < n: + arr.append(B[index_B]) + index_B += 1 + for i in range(m + n): + A[i] = arr[i] +``` + +### 思路 1:复杂度分析 + +- **时间复杂度**:$O(m + n)$。 +- **空间复杂度**:$O(m + n)$。 + diff --git a/docs/solutions/interviews/successor-lcci.md b/docs/solutions/interviews/successor-lcci.md new file mode 100644 index 00000000..0576afea --- /dev/null +++ b/docs/solutions/interviews/successor-lcci.md @@ -0,0 +1,39 @@ +# [面试题 04.06. 后继者](https://leetcode.cn/problems/successor-lcci/) + +- 标签:树、深度优先搜索、二叉搜索树、二叉树 +- 难度:中等 + +## 题目链接 + +- [面试题 04.06. 后继者 - 力扣](https://leetcode.cn/problems/successor-lcci/) + +## 题目大意 + +给定一棵二叉搜索树的根节点 `root` 和其中一个节点 `p`。 + +要求:找出该节点在树中的中序后继,即按照中序遍历的顺序节点 `p` 的下一个节点。如果节点 `p` 没有对应的下一个节点,则返回 `None`。 + +## 解题思路 + +递归遍历,具体步骤如下: + +- 如果 `root.val` 小于等于 `p.val`,则直接从 `root` 的右子树递归查找比 `p.val` 大的节点,从而找到中序后继。 +- 如果 `root.val` 大于 `p.val`,则 `root` 有可能是中序后继,也有可能是 `root` 的左子树。则从 `root` 的左子树递归查找更接近(更小的)。如果查找的值为 `None`,则当前 `root` 就是中序后继,否则继续递归查找,从而找到中序后继。 + +## 代码 + +```python +class Solution: + def inorderSuccessor(self, root: TreeNode, p: TreeNode) -> TreeNode: + if not p or not root: + return None + + if root.val <= p.val: + node = self.inorderSuccessor(root.right, p) + else: + node = self.inorderSuccessor(root.left, p) + if not node: + node = root + return node +``` + diff --git a/docs/solutions/interviews/sum-lists-lcci.md b/docs/solutions/interviews/sum-lists-lcci.md new file mode 100644 index 00000000..7962b73d --- /dev/null +++ b/docs/solutions/interviews/sum-lists-lcci.md @@ -0,0 +1,47 @@ +# [面试题 02.05. 链表求和](https://leetcode.cn/problems/sum-lists-lcci/) + +- 标签:递归、链表、数学 +- 难度:中等 + +## 题目链接 + +- [面试题 02.05. 链表求和 - 力扣](https://leetcode.cn/problems/sum-lists-lcci/) + +## 题目大意 + +给定两个非空的链表 `l1` 和 `l2`,表示两个非负整数,每位数字都是按照逆序的方式存储的,每个节点存储一位数字。 + +要求:计算两个整数的和,并逆序返回表示和的链表。 + +## 解题思路 + +模拟大数加法,按位相加,将结果添加到新链表上。需要注意进位和对 `10` 取余。 + +## 代码 + +```python +class Solution: + def addTwoNumbers(self, l1: ListNode, l2: ListNode) -> ListNode: + head = curr = ListNode(0) + carry = 0 + while l1 or l2 or carry: + if l1: + num1 = l1.val + l1 = l1.next + else: + num1 = 0 + if l2: + num2 = l2.val + l2 = l2.next + else: + num2 = 0 + + sum = num1 + num2 + carry + carry = sum // 10 + + curr.next = ListNode(sum % 10) + curr = curr.next + + return head.next +``` + diff --git a/docs/solutions/interviews/words-frequency-lcci.md b/docs/solutions/interviews/words-frequency-lcci.md new file mode 100644 index 00000000..6211c194 --- /dev/null +++ b/docs/solutions/interviews/words-frequency-lcci.md @@ -0,0 +1,78 @@ +# [面试题 16.02. 单词频率](https://leetcode.cn/problems/words-frequency-lcci/) + +- 标签:设计、字典树、数组、哈希表、字符串 +- 难度:中等 + +## 题目链接 + +- [面试题 16.02. 单词频率 - 力扣](https://leetcode.cn/problems/words-frequency-lcci/) + +## 题目大意 + +要求:设计一个方法,找出任意指定单词在一本书中的出现频率。 + +支持如下操作: + +- `WordsFrequency(book)` 构造函数,参数为字符串数组构成的一本书。 +- `get(word)` 查询指定单词在书中出现的频率。 + +## 解题思路 + +使用字典树统计单词频率。 + +构造函数时,构建一个字典树,并将所有单词存入字典树中,同时在字典树中记录并维护单词频率。 + +查询时,调用字典树查询方法,查询单词频率。 + +## 代码 + +```python +class Trie: + + def __init__(self): + """ + Initialize your data structure here. + """ + self.children = dict() + self.isEnd = False + self.count = 0 + + + def insert(self, word: str) -> None: + """ + Inserts a word into the trie. + """ + cur = self + for ch in word: + if ch not in cur.children: + cur.children[ch] = Trie() + cur = cur.children[ch] + cur.isEnd = True + cur.count += 1 + + + def search(self, word: str) -> bool: + """ + Returns if the word is in the trie. + """ + cur = self + for ch in word: + if ch not in cur.children: + return 0 + cur = cur.children[ch] + if cur and cur.isEnd: + return cur.count + return 0 + +class WordsFrequency: + + def __init__(self, book: List[str]): + self.tire_tree = Trie() + for word in book: + self.tire_tree.insert(word) + + + def get(self, word: str) -> int: + return self.tire_tree.search(word) +``` + diff --git a/docs/solutions/interviews/zero-matrix-lcci.md b/docs/solutions/interviews/zero-matrix-lcci.md new file mode 100644 index 00000000..6f9f855b --- /dev/null +++ b/docs/solutions/interviews/zero-matrix-lcci.md @@ -0,0 +1,70 @@ +# [面试题 01.08. 零矩阵](https://leetcode.cn/problems/zero-matrix-lcci/) + +- 标签:数组、哈希表、矩阵 +- 难度:中等 + +## 题目链接 + +- [面试题 01.08. 零矩阵 - 力扣](https://leetcode.cn/problems/zero-matrix-lcci/) + +## 题目大意 + +给定一个 `m * n` 大小的二维矩阵 `matrix`。 + +要求:编写一种算法,如果矩阵中某个元素为 `0`,增将其所在行与列清零。 + +## 解题思路 + +直观上可以使用两个数组或者集合来标记行和列出现 `0` 的情况,但更好的做法是不用开辟新的数组或集合,直接原本二维矩阵 `matrix` 的空间。使用数组原本的元素进行记录出现 0 的情况。 + +设定两个变量 `flag_row0`、`flag_col0` 来标记第一行、第一列是否出现了 `0`。 + +接下来我们使用数组第一行、第一列来标记 `0` 的情况。 + +对数组除第一行、第一列之外的每个元素进行遍历,如果某个元素出现 `0` 了,则使用数组的第一行、第一列对应位置来存储 `0` 的标记。 + +再对数组除第一行、第一列之外的每个元素进行遍历,通过对第一行、第一列的标记 0 情况,进行置为 `0` 的操作。 + +最后再根据 `flag_row0`、`flag_col0` 的标记情况,对第一行、第一列进行置为 `0` 的操作。 + +## 代码 + +```python +class Solution: + def setZeroes(self, matrix: List[List[int]]) -> None: + """ + Do not return anything, modify matrix in-place instead. + """ + rows = len(matrix) + cols = len(matrix[0]) + flag_col0 = False + flag_row0 = False + for i in range(rows): + if matrix[i][0] == 0: + flag_col0 = True + break + + for j in range(cols): + if matrix[0][j] == 0: + flag_row0 = True + break + + for i in range(1, rows): + for j in range(1, cols): + if matrix[i][j] == 0: + matrix[i][0] = matrix[0][j] = 0 + + for i in range(1, rows): + for j in range(1, cols): + if matrix[i][0] == 0 or matrix[0][j] == 0: + matrix[i][j] = 0 + + if flag_col0: + for i in range(rows): + matrix[i][0] = 0 + + if flag_row0: + for j in range(cols): + matrix[0][j] = 0 +``` +