From bc4507a22681f2bd0e95afb42d99eb2c6afbd589 Mon Sep 17 00:00:00 2001 From: kkty39 Date: Sun, 4 Jun 2023 15:23:45 -0700 Subject: [PATCH 1/5] fix code: java 22 --- .../solution_code.md" | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git "a/\345\244\232\350\257\255\350\250\200\350\247\243\346\263\225\344\273\243\347\240\201/solution_code.md" "b/\345\244\232\350\257\255\350\250\200\350\247\243\346\263\225\344\273\243\347\240\201/solution_code.md" index 4356b52865..a12af519a7 100644 --- "a/\345\244\232\350\257\255\350\250\200\350\247\243\346\263\225\344\273\243\347\240\201/solution_code.md" +++ "b/\345\244\232\350\257\255\350\250\200\350\247\243\346\263\225\344\273\243\347\240\201/solution_code.md" @@ -26875,13 +26875,13 @@ func backtrack(left int, right int, track *string, res *[]string) { ```java // by labuladong (java) class Solution { - public: - vector generateParenthesis(int n) { - if (n == 0) return {}; + + public List generateParenthesis(int n) { + if (n == 0) return new ArrayList<>(); // 记录所有合法的括号组合 - vector res; + List res = new ArrayList<>(); // 回溯过程中的路径 - string track; + StringBuilder track = new StringBuilder(); // 可用的左括号和右括号数量初始化为 n backtrack(n, n, track, res); return res; @@ -26889,26 +26889,26 @@ class Solution { // 可用的左括号数量为 left 个,可用的右括号数量为 rgiht 个 void backtrack(int left, int right, - string& track, vector& res) { + StringBuilder track, List res) { // 若左括号剩下的多,说明不合法 if (right < left) return; // 数量小于 0 肯定是不合法的 if (left < 0 || right < 0) return; // 当所有括号都恰好用完时,得到一个合法的括号组合 if (left == 0 && right == 0) { - res.push_back(track); + res.add(track.toString()); return; } // 尝试放一个左括号 - track.push_back('('); // 选择 + track.append('('); // 选择 backtrack(left - 1, right, track, res); - track.pop_back(); // 撤消选择 + track.deleteCharAt(track.length() - 1); // 撤消选择 // 尝试放一个右括号 - track.push_back(')'); // 选择 + track.append(')'); // 选择 backtrack(left, right - 1, track, res); - track.pop_back(); // 撤消选择 + track.deleteCharAt(track.length() - 1); // 撤消选择 } } ``` From 11dc74f028107441bd98786be1c5295ac490634e Mon Sep 17 00:00:00 2001 From: kkty39 Date: Sun, 4 Jun 2023 15:25:00 -0700 Subject: [PATCH 2/5] fix code: java 22 --- .../solution_code.md" | 1 - 1 file changed, 1 deletion(-) diff --git "a/\345\244\232\350\257\255\350\250\200\350\247\243\346\263\225\344\273\243\347\240\201/solution_code.md" "b/\345\244\232\350\257\255\350\250\200\350\247\243\346\263\225\344\273\243\347\240\201/solution_code.md" index a12af519a7..cbed11abe5 100644 --- "a/\345\244\232\350\257\255\350\250\200\350\247\243\346\263\225\344\273\243\347\240\201/solution_code.md" +++ "b/\345\244\232\350\257\255\350\250\200\350\247\243\346\263\225\344\273\243\347\240\201/solution_code.md" @@ -26875,7 +26875,6 @@ func backtrack(left int, right int, track *string, res *[]string) { ```java // by labuladong (java) class Solution { - public List generateParenthesis(int n) { if (n == 0) return new ArrayList<>(); // 记录所有合法的括号组合 From ca21eab7cb8d86e711d9f1f7efd27bab10aa3b63 Mon Sep 17 00:00:00 2001 From: kkty39 Date: Sun, 4 Jun 2023 16:42:24 -0700 Subject: [PATCH 3/5] fix typo in comment --- .../solution_code.md" | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git "a/\345\244\232\350\257\255\350\250\200\350\247\243\346\263\225\344\273\243\347\240\201/solution_code.md" "b/\345\244\232\350\257\255\350\250\200\350\247\243\346\263\225\344\273\243\347\240\201/solution_code.md" index cbed11abe5..3de3bfeee2 100644 --- "a/\345\244\232\350\257\255\350\250\200\350\247\243\346\263\225\344\273\243\347\240\201/solution_code.md" +++ "b/\345\244\232\350\257\255\350\250\200\350\247\243\346\263\225\344\273\243\347\240\201/solution_code.md" @@ -26803,7 +26803,7 @@ public: return res; } - // 可用的左括号数量为 left 个,可用的右括号数量为 rgiht 个 + // 可用的左括号数量为 left 个,可用的右括号数量为 right 个 void backtrack(int left, int right, string& track, vector& res) { // 若左括号剩下的多,说明不合法 @@ -26844,7 +26844,7 @@ func generateParenthesis(n int) []string { return res } -// 可用的左括号数量为 left 个,可用的右括号数量为 rgiht 个 +// 可用的左括号数量为 left 个,可用的右括号数量为 right 个 func backtrack(left int, right int, track *string, res *[]string) { // 若左括号剩下的多,说明不合法 if right < left { @@ -26886,7 +26886,7 @@ class Solution { return res; } - // 可用的左括号数量为 left 个,可用的右括号数量为 rgiht 个 + // 可用的左括号数量为 left 个,可用的右括号数量为 right 个 void backtrack(int left, int right, StringBuilder track, List res) { // 若左括号剩下的多,说明不合法 @@ -26925,7 +26925,7 @@ var generateParenthesis = function(n) { return res; }; -// 可用的左括号数量为 left 个,可用的右括号数量为 rgiht 个 +// 可用的左括号数量为 left 个,可用的右括号数量为 right 个 function backtrack(left, right, track, res) { // 若左括号剩下的多,说明不合法 if (right < left) return; @@ -26963,7 +26963,7 @@ class Solution: self.backtrack(n, n, track, res) return res - # 可用的左括号数量为 left 个,可用的右括号数量为 rgiht 个 + # 可用的左括号数量为 left 个,可用的右括号数量为 right 个 def backtrack(self, left, right, track, res): # 若左括号剩下的多,说明不合法 if right < left: @@ -53157,7 +53157,7 @@ func deleteDuplicates(head *ListNode) *ListNode { ```java // by labuladong (java) class Solution { - public deleteDuplicates(ListNode head) { + public ListNode deleteDuplicates(ListNode head) { if (head == null) return null; ListNode slow = head, fast = head; while (fast != null) { From af3ca8d98257d6930b7b49bc5a7a63441f811157 Mon Sep 17 00:00:00 2001 From: kkty39 Date: Sun, 4 Jun 2023 16:44:18 -0700 Subject: [PATCH 4/5] remove fixes in another problem --- .../solution_code.md" | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git "a/\345\244\232\350\257\255\350\250\200\350\247\243\346\263\225\344\273\243\347\240\201/solution_code.md" "b/\345\244\232\350\257\255\350\250\200\350\247\243\346\263\225\344\273\243\347\240\201/solution_code.md" index 3de3bfeee2..c1b39bbaa2 100644 --- "a/\345\244\232\350\257\255\350\250\200\350\247\243\346\263\225\344\273\243\347\240\201/solution_code.md" +++ "b/\345\244\232\350\257\255\350\250\200\350\247\243\346\263\225\344\273\243\347\240\201/solution_code.md" @@ -53157,7 +53157,7 @@ func deleteDuplicates(head *ListNode) *ListNode { ```java // by labuladong (java) class Solution { - public ListNode deleteDuplicates(ListNode head) { + public deleteDuplicates(ListNode head) { if (head == null) return null; ListNode slow = head, fast = head; while (fast != null) { From fb3b506b0c054032d202c3e6c7dda42f0e1502e8 Mon Sep 17 00:00:00 2001 From: labuladong Date: Fri, 9 Jun 2023 21:26:24 +0800 Subject: [PATCH 5/5] update content --- ...41\347\245\250\351\227\256\351\242\230.md" | 2 +- .../solution_code.md" | 965 +++++++++++++++++- ...45\346\211\276\350\257\246\350\247\243.md" | 80 +- ...43\344\277\256\350\256\242\347\211\210.md" | 2 +- ...00\345\267\247\350\277\233\351\230\266.md" | 4 +- 5 files changed, 995 insertions(+), 58 deletions(-) diff --git "a/\345\212\250\346\200\201\350\247\204\345\210\222\347\263\273\345\210\227/\345\233\242\347\201\255\350\202\241\347\245\250\351\227\256\351\242\230.md" "b/\345\212\250\346\200\201\350\247\204\345\210\222\347\263\273\345\210\227/\345\233\242\347\201\255\350\202\241\347\245\250\351\227\256\351\242\230.md" index 8d664be96d..a8d5d3b9c6 100644 --- "a/\345\212\250\346\200\201\350\247\204\345\210\222\347\263\273\345\210\227/\345\233\242\347\201\255\350\202\241\347\245\250\351\227\256\351\242\230.md" +++ "b/\345\212\250\346\200\201\350\247\204\345\210\222\347\263\273\345\210\227/\345\233\242\347\201\255\350\202\241\347\245\250\351\227\256\351\242\230.md" @@ -140,7 +140,7 @@ dp[i][k][1] = max(dp[i-1][k][1], dp[i-1][k-1][0] - prices[i]) 2、我昨天本没有持有,且截至昨天最大交易次数限制为 `k - 1`;但今天我选择 `buy`,所以今天我就持有股票了,最大交易次数限制为 `k`。 -> note:这里着重提醒一下,**时刻牢记「状态」的定义**,状态 `k` 的定义并不是「已进行的交易次数」,而是「最大交易次数的上限限制」。如果确定今天进行一次交易,且要保证截至今天最大交易次数上限为 `k`,那么昨天的最大交易次数上限必须是 `k - 1`。 +> note:这里着重提醒一下,**时刻牢记「状态」的定义**,状态 `k` 的定义并不是「已进行的交易次数」,而是「最大交易次数的上限限制」。如果确定今天进行一次交易,且要保证截至今天最大交易次数上限为 `k`,那么昨天的最大交易次数上限必须是 `k - 1`。举个具体的例子,比方说要求你的银行卡里今天至少有 100 块钱,且你确定你今天可以赚 10 块钱,那么你就要保证昨天的银行卡要至少剩下 90 块钱。 这个解释应该很清楚了,如果 `buy`,就要从利润中减去 `prices[i]`,如果 `sell`,就要给利润增加 `prices[i]`。今天的最大利润就是这两种可能选择中较大的那个。 diff --git "a/\345\244\232\350\257\255\350\250\200\350\247\243\346\263\225\344\273\243\347\240\201/solution_code.md" "b/\345\244\232\350\257\255\350\250\200\350\247\243\346\263\225\344\273\243\347\240\201/solution_code.md" index c1b39bbaa2..59e52d4bdd 100644 --- "a/\345\244\232\350\257\255\350\250\200\350\247\243\346\263\225\344\273\243\347\240\201/solution_code.md" +++ "b/\345\244\232\350\257\255\350\250\200\350\247\243\346\263\225\344\273\243\347\240\201/solution_code.md" @@ -336,40 +336,39 @@ class Solution { ```javascript // by chatGPT (javascript) -let memo; - var minPathSum = function(grid) { - const m = grid.length; - const n = grid[0].length; + var m = grid.length; + var n = grid[0].length; // 构造备忘录,初始值全部设为 -1 - memo = new Array(m); - for (let i = 0; i < m; i++) { - memo[i] = new Array(n).fill(-1); + var memo = new Array(m); + for (var i = 0; i < memo.length; i++) { + memo[i] = new Array(n); + memo[i].fill(-1); } - return dp(grid, m - 1, n - 1); + return dp(grid, m - 1, n - 1, memo); }; -var dp = function(grid, i, j) { +function dp(grid, i, j, memo) { // base case - if (i === 0 && j === 0) { + if (i == 0 && j == 0) { return grid[0][0]; } if (i < 0 || j < 0) { - return Number.MAX_SAFE_INTEGER; + return Number.MAX_VALUE; } // 避免重复计算 - if (memo[i][j] !== -1) { + if (memo[i][j] != -1) { return memo[i][j]; } // 将计算结果记入备忘录 memo[i][j] = Math.min( - dp(grid, i - 1, j), - dp(grid, i, j - 1) - ) + grid[i][j]; + dp(grid, i - 1, j, memo), + dp(grid, i, j - 1, memo) + ) + grid[i][j]; return memo[i][j]; -}; +} ``` ```python @@ -2541,9 +2540,9 @@ https://leetcode.cn/problems/Gu0c2T 的多语言解法👆 https://leetcode.cn/problems/IDBivT 的多语言解法👇 ```cpp -// by chatGPT (cpp) +// by labuladong (cpp) class Solution { -public: + public: vector generateParenthesis(int n) { if (n == 0) return {}; // 记录所有合法的括号组合 @@ -2556,7 +2555,7 @@ public: } // 可用的左括号数量为 left 个,可用的右括号数量为 rgiht 个 - void backtrack(int left, int right, + void backtrack(int left, int right, string& track, vector& res) { // 若左括号剩下的多,说明不合法 if (right < left) return; @@ -2567,7 +2566,7 @@ public: res.push_back(track); return; } - + // 尝试放一个左括号 track.push_back('('); // 选择 backtrack(left - 1, right, track, res); @@ -2578,7 +2577,7 @@ public: backtrack(left, right - 1, track, res); track.pop_back(); // 撤消选择 } -}; +} ``` ```go @@ -26789,9 +26788,9 @@ https://leetcode.cn/problems/gas-station 的多语言解法👆 https://leetcode.cn/problems/generate-parentheses 的多语言解法👇 ```cpp -// by chatGPT (cpp) +// by labuladong (cpp) class Solution { -public: + public: vector generateParenthesis(int n) { if (n == 0) return {}; // 记录所有合法的括号组合 @@ -26803,8 +26802,8 @@ public: return res; } - // 可用的左括号数量为 left 个,可用的右括号数量为 right 个 - void backtrack(int left, int right, + // 可用的左括号数量为 left 个,可用的右括号数量为 rgiht 个 + void backtrack(int left, int right, string& track, vector& res) { // 若左括号剩下的多,说明不合法 if (right < left) return; @@ -26815,7 +26814,7 @@ public: res.push_back(track); return; } - + // 尝试放一个左括号 track.push_back('('); // 选择 backtrack(left - 1, right, track, res); @@ -26826,7 +26825,7 @@ public: backtrack(left, right - 1, track, res); track.pop_back(); // 撤消选择 } -}; +} ``` ```go @@ -40830,6 +40829,242 @@ class Solution: https://leetcode.cn/problems/minimum-falling-path-sum 的多语言解法👆 +https://leetcode.cn/problems/minimum-height-trees 的多语言解法👇 + +```cpp +// by chatGPT (cpp) +class Solution { +public: + vector findMinHeightTrees(int n, vector>& edges) { + // 1、构建邻接表 + vector> graph(n); + for (auto& edge : edges) { + // 无向图,等同于双向图 + graph[edge[0]].push_back(edge[1]); + graph[edge[1]].push_back(edge[0]); + } + + // 2、找到所有的叶子节点 + vector leaves; + for (int i = 0; i < n; i++) { + if (graph[i].size() == 1) { + leaves.push_back(i); + } + } + + // 3、不断删除叶子节点,直到剩下的节点数小于等于 2 个 + int remainNodeNum = n; + while (remainNodeNum > 2) { + // 删除当前叶子节点,计算新的叶子节点 + remainNodeNum -= leaves.size(); + vector newLeaves; + for (auto leaf : leaves) { + // 将被删除的叶子节点的邻接节点的度减 1 + int neighbor = graph[leaf][0]; + graph[neighbor].erase(find(graph[neighbor].begin(), graph[neighbor].end(), leaf)); + // 如果邻接节点的度为 1,说明它也变成了叶子节点 + if (graph[neighbor].size() == 1) { + newLeaves.push_back(neighbor); + } + } + leaves = newLeaves; + } + + // 最后剩下的节点就是根节点 + return leaves; + } +}; +``` + +```go +// by chatGPT (go) +func findMinHeightTrees(n int, edges [][]int) []int { + // 1、构建邻接表 + graph := make([][]int, n) + for i := 0; i < n; i++ { + graph[i] = []int{} + } + for _, edge := range edges { + // 无向图,等同于双向图 + graph[edge[0]] = append(graph[edge[0]], edge[1]) + graph[edge[1]] = append(graph[edge[1]], edge[0]) + } + + // 2、找到所有的叶子节点 + leaves := []int{} + for i := 0; i < n; i++ { + if len(graph[i]) == 1 { + leaves = append(leaves, i) + } + } + + // 3、不断删除叶子节点,直到剩下的节点数小于等于 2 个 + remainNodeNum := n + for remainNodeNum > 2 { + // 删除当前叶子节点,计算新的叶子节点 + remainNodeNum -= len(leaves) + newLeaves := []int{} + for _, leaf := range leaves { + // 将被删除的叶子节点的邻接节点的度减 1 + neighbor := graph[leaf][0] + graph[neighbor] = removeElement(graph[neighbor], leaf) + // 如果邻接节点的度为 1,说明它也变成了叶子节点 + if len(graph[neighbor]) == 1 { + newLeaves = append(newLeaves, neighbor) + } + } + leaves = newLeaves + } + + // 最后剩下的节点就是根节点 + return leaves +} + +// 删除切片中的元素 +func removeElement(slice []int, elem int) []int { + index := -1 + for i, v := range slice { + if v == elem { + index = i + break + } + } + if index == -1 { + return slice + } + return append(slice[:index], slice[index+1:]...) +} +``` + +```java +// by labuladong (java) +class Solution { + public List findMinHeightTrees(int n, int[][] edges) { + // 1、构建邻接表 + List> graph = new ArrayList<>(); + for (int i = 0; i < n; i++) { + graph.add(new ArrayList()); + } + for (int[] edge : edges) { + // 无向图,等同于双向图 + graph.get(edge[0]).add(edge[1]); + graph.get(edge[1]).add(edge[0]); + } + + // 2、找到所有的叶子节点 + List leaves = new ArrayList<>(); + for (int i = 0; i < n; i++) { + if (graph.get(i).size() == 1) { + leaves.add(i); + } + } + + // 3、不断删除叶子节点,直到剩下的节点数小于等于 2 个 + int remainNodeNum = n; + while (remainNodeNum > 2) { + // 删除当前叶子节点,计算新的叶子节点 + remainNodeNum -= leaves.size(); + List newLeaves = new ArrayList<>(); + for (int leaf : leaves) { + // 将被删除的叶子节点的邻接节点的度减 1 + int neighbor = graph.get(leaf).get(0); + graph.get(neighbor).remove(leaf); + // 如果邻接节点的度为 1,说明它也变成了叶子节点 + if (graph.get(neighbor).size() == 1) { + newLeaves.add(neighbor); + } + } + + // 最后剩下的节点就是根节点 + return leaves; + } +} +``` + +```javascript +// by chatGPT (javascript) +var findMinHeightTrees = function(n, edges) { + // 1、构建邻接表 + let graph = new Array(n); + for(let i = 0; i < n; i++) { + graph[i] = []; + } + for(let edge of edges) { + // 无向图,等同于双向图 + graph[edge[0]].push(edge[1]); + graph[edge[1]].push(edge[0]); + } + + // 2、找到所有的叶子节点 + let leaves = []; + for(let i = 0; i < n; i++) { + if(graph[i].length === 1) { + leaves.push(i); + } + } + + // 3、不断删除叶子节点,直到剩下的节点数小于等于 2 个 + let remainNodeNum = n; + while(remainNodeNum > 2) { + // 删除当前叶子节点,计算新的叶子节点 + remainNodeNum -= leaves.length; + let newLeaves = []; + for(let leaf of leaves) { + // 将被删除的叶子节点的邻接节点的度减 1 + let neighbor = graph[leaf][0]; + graph[neighbor].splice(graph[neighbor].indexOf(leaf), 1); + // 如果邻接节点的度为 1,说明它也变成了叶子节点 + if(graph[neighbor].length === 1) { + newLeaves.push(neighbor); + } + } + leaves = newLeaves; + } + + // 最后剩下的节点就是根节点 + return leaves; +}; +``` + +```python +# by chatGPT (python) +class Solution: + def findMinHeightTrees(self, n: int, edges: List[List[int]]) -> List[int]: + # 1、构建邻接表 + graph = [[] for _ in range(n)] + for edge in edges: + # 无向图,等同于双向图 + graph[edge[0]].append(edge[1]) + graph[edge[1]].append(edge[0]) + + # 2、找到所有的叶子节点 + leaves = [] + for i in range(n): + if len(graph[i]) == 1: + leaves.append(i) + + # 3、不断删除叶子节点,直到剩下的节点数小于等于 2 个 + remainNodeNum = n + while remainNodeNum > 2: + # 删除当前叶子节点,计算新的叶子节点 + remainNodeNum -= len(leaves) + newLeaves = [] + for leaf in leaves: + # 将被删除的叶子节点的邻接节点的度减 1 + neighbor = graph[leaf][0] + graph[neighbor].remove(leaf) + # 如果邻接节点的度为 1,说明它也变成了叶子节点 + if len(graph[neighbor]) == 1: + newLeaves.append(neighbor) + + leaves = newLeaves + + # 最后剩下的节点就是根节点 + return leaves +``` + +https://leetcode.cn/problems/minimum-height-trees 的多语言解法👆 + https://leetcode.cn/problems/minimum-insertions-to-balance-a-parentheses-string 的多语言解法👇 ```cpp @@ -43242,6 +43477,221 @@ class Solution: https://leetcode.cn/problems/nZZqjQ 的多语言解法👆 +https://leetcode.cn/problems/nearest-exit-from-entrance-in-maze 的多语言解法👇 + +```cpp +// by chatGPT (cpp) +class Solution { +public: + int nearestExit(vector>& maze, vector& entrance) { + int m = maze.size(); + int n = maze[0].size(); + vector> dirs {{0, 1}, {0, -1}, {1, 0}, {-1, 0}}; + + // BFS 算法的队列和 visited 数组 + queue> queue; + vector> visited(m, vector(n, false)); + queue.push(entrance); + visited[entrance[0]][entrance[1]] = true; + // 启动 BFS 算法从 entrance 开始像四周扩散 + int step = 0; + while (!queue.empty()) { + int sz = queue.size(); + step++; + // 扩散当前队列中的所有节点 + for (int i = 0; i < sz; i++) { + vector cur = queue.front(); + queue.pop(); + // 每个节点都会尝试向上下左右四个方向扩展一步 + for (vector dir : dirs) { + int x = cur[0] + dir[0]; + int y = cur[1] + dir[1]; + if (x < 0 || x >= m || y < 0 || y >= n + || visited[x][y] || maze[x][y] == '+') { + continue; + } + if (x == 0 || x == m - 1 || y == 0 || y == n - 1) { + // 走到边界(出口) + return step; + } + visited[x][y] = true; + queue.push(vector{x, y}); + } + } + } + return -1; + } +}; +``` + +```go +// by chatGPT (go) +func nearestExit(maze [][]byte, entrance []int) int { + m, n := len(maze), len(maze[0]) + dirs := [][]int{{0, 1}, {0, -1}, {1, 0}, {-1, 0}} + + // BFS 算法的队列和 visited 数组 + queue := [][]int{entrance} + visited := make([][]bool, m) + for i := 0; i < m; i++ { + visited[i] = make([]bool, n) + } + visited[entrance[0]][entrance[1]] = true + // 启动 BFS 算法从 entrance 开始像四周扩散 + step := 0 + for len(queue) > 0 { + sz := len(queue) + step++ + // 扩散当前队列中的所有节点 + for i := 0; i < sz; i++ { + cur := queue[0] + queue = queue[1:] + // 每个节点都会尝试向上下左右四个方向扩展一步 + for _, dir := range dirs { + x := cur[0] + dir[0] + y := cur[1] + dir[1] + if x < 0 || x >= m || y < 0 || y >= n || visited[x][y] || maze[x][y] == '+' { + continue + } + if x == 0 || x == m-1 || y == 0 || y == n-1 { + // 走到边界(出口) + return step + } + visited[x][y] = true + queue = append(queue, []int{x, y}) + } + } + } + return -1 +} +``` + +```java +// by labuladong (java) +class Solution { + public int nearestExit(char[][] maze, int[] entrance) { + int m = maze.length; + int n = maze[0].length; + int[][] dirs = {{0, 1}, {0, -1}, {1, 0}, {-1, 0}}; + + // BFS 算法的队列和 visited 数组 + Queue queue = new LinkedList<>(); + boolean[][] visited = new boolean[m][n]; + queue.offer(entrance); + visited[entrance[0]][entrance[1]] = true; + // 启动 BFS 算法从 entrance 开始像四周扩散 + int step = 0; + while (!queue.isEmpty()) { + int sz = queue.size(); + step++; + // 扩散当前队列中的所有节点 + for (int i = 0; i < sz; i++) { + int[] cur = queue.poll(); + // 每个节点都会尝试向上下左右四个方向扩展一步 + for (int[] dir : dirs) { + int x = cur[0] + dir[0]; + int y = cur[1] + dir[1]; + if (x < 0 || x >= m || y < 0 || y >= n + || visited[x][y] || maze[x][y] == '+') { + continue; + } + if (x == 0 || x == m - 1 || y == 0 || y == n - 1) { + // 走到边界(出口) + return step; + } + visited[x][y] = true; + queue.offer(new int[]{x, y}); + } + } + } + return -1; + } +} +``` + +```javascript +// by chatGPT (javascript) +var nearestExit = function(maze, entrance) { + const m = maze.length; + const n = maze[0].length; + const dirs = [[0, 1], [0, -1], [1, 0], [-1, 0]]; + + // BFS 算法的队列和 visited 数组 + const queue = []; + const visited = Array(m).fill(0).map(() => Array(n).fill(false)); + queue.push(entrance); + visited[entrance[0]][entrance[1]] = true; + + // 启动 BFS 算法从 entrance 开始像四周扩散 + let step = 0; + while (queue.length) { + const sz = queue.length; + step++; + + // 扩散当前队列中的所有节点 + for (let i = 0; i < sz; i++) { + const cur = queue.shift(); + + // 每个节点都会尝试向上下左右四个方向扩展一步 + for (const dir of dirs) { + const x = cur[0] + dir[0]; + const y = cur[1] + dir[1]; + + if (x < 0 || x >= m || y < 0 || y >= n || visited[x][y] || maze[x][y] === '+') { + continue; + } + + if (x === 0 || x === m - 1 || y === 0 || y === n - 1) { + // 走到边界(出口) + return step; + } + + visited[x][y] = true; + queue.push([x, y]); + } + } + } + + return -1; +}; +``` + +```python +# by chatGPT (python) +class Solution: + def nearestExit(self, maze: List[List[str]], entrance: List[int]) -> int: + m, n = len(maze), len(maze[0]) + dirs = [(0, 1), (0, -1), (1, 0), (-1, 0)] + + # BFS 算法的队列和 visited 数组 + queue = deque() + visited = [[False] * n for _ in range(m)] + queue.append(tuple(entrance)) + visited[entrance[0]][entrance[1]] = True + # 启动 BFS 算法从 entrance 开始像四周扩散 + step = 0 + while queue: + sz = len(queue) + step += 1 + # 扩散当前队列中的所有节点 + for _ in range(sz): + cur_x, cur_y = queue.popleft() + # 每个节点都会尝试向上下左右四个方向扩展一步 + for dir_x, dir_y in dirs: + nxt_x, nxt_y = cur_x + dir_x, cur_y + dir_y + if nxt_x < 0 or nxt_x >= m or nxt_y < 0 or nxt_y >= n \ + or visited[nxt_x][nxt_y] or maze[nxt_x][nxt_y] == '+': + continue + if nxt_x == 0 or nxt_x == m - 1 or nxt_y == 0 or nxt_y == n - 1: + # 走到边界(出口) + return step + visited[nxt_x][nxt_y] = True + queue.append((nxt_x, nxt_y)) + return -1 +``` + +https://leetcode.cn/problems/nearest-exit-from-entrance-in-maze 的多语言解法👆 + https://leetcode.cn/problems/network-delay-time 的多语言解法👇 ```cpp @@ -61990,6 +62440,465 @@ class Solution: https://leetcode.cn/problems/target-sum 的多语言解法👆 +https://leetcode.cn/problems/the-maze 的多语言解法👇 + +```cpp +// by chatGPT (cpp) +class Solution { +public: + bool hasPath(vector>& maze, vector& start, vector& destination) { + int m = maze.size(), n = maze[0].size(); + // 方向数组,方便上下左右移动 + int dirs[4][2] = {{0,1},{0,-1},{1,0},{-1,0}}; + + // BFS 算法的队列和 visited 数组 + queue> q; + vector> visited(m, vector(n, false)); + // 加入起点 + q.push(start); + visited[start[0]][start[1]] = true; + // 启动 BFS 算法框架 + while (!q.empty()) { + vector cur = q.front(); + q.pop(); + // 向四个方向扩展 + for (auto dir : dirs) { + int x = cur[0], y = cur[1]; + // 和其他题目不同的是,这里一直走到墙,而不是只走一步 + while (x >= 0 && x < m && y >= 0 && y < n && maze[x][y] == 0) { + x += dir[0]; + y += dir[1]; + } + x -= dir[0]; + y -= dir[1]; + // 判断是否到达终点 + if (x == destination[0] && y == destination[1]) { + return true; + } + if (!visited[x][y]) { + visited[x][y] = true; + q.push({x, y}); + } + } + } + return false; + } +}; +``` + +```go +// by chatGPT (go) +import "fmt" + +func hasPath(maze [][]int, start []int, destination []int) bool { + m, n := len(maze), len(maze[0]) + // 方向数组,方便上下左右移动 + dirs := [][]int{{0, 1}, {0, -1}, {1, 0}, {-1, 0}} + + q := [][]int{start} + visited := make([][]bool, m) + for i := range visited { + visited[i] = make([]bool, n) + } + visited[start[0]][start[1]] = true + + // 启动 BFS 算法框架 + for len(q) > 0 { + cur := q[0] + q = q[1:] + // 向四个方向扩展 + for _, dir := range dirs { + x, y := cur[0], cur[1] + // 和其他题目不同的是,这里一直走到墙,而不是只走一步 + for x >= 0 && x < m && y >= 0 && y < n && maze[x][y] == 0 { + x += dir[0] + y += dir[1] + } + x -= dir[0] + y -= dir[1] + // 判断是否到达终点 + if x == destination[0] && y == destination[1] { + return true + } + if !visited[x][y] { + visited[x][y] = true + q = append(q, []int{x, y}) + } + } + } + return false +} + +func main() { + maze := [][]int{ + {0,0,1,0,0}, + {0,0,0,0,0}, + {0,0,0,1,0}, + {1,1,0,1,1}, + {0,0,0,0,0}, + } + start := []int{0, 4} + destination := []int{4, 4} + fmt.Println(hasPath(maze, start, destination)) // Output: true +} +``` + +```java +// by labuladong (java) +class Solution { + public boolean hasPath(int[][] maze, int[] start, int[] destination) { + int m = maze.length, n = maze[0].length; + // 方向数组,方便上下左右移动 + int[][] dirs = {{0,1},{0,-1},{1,0},{-1,0}}; + + // BFS 算法的队列和 visited 数组 + Queue q = new LinkedList<>(); + boolean[][] visited = new boolean[m][n]; + // 加入起点 + q.offer(start); + visited[start[0]][start[1]] = true; + // 启动 BFS 算法框架 + while (!q.isEmpty()) { + int[] cur = q.poll(); + // 向四个方向扩展 + for (int[] dir : dirs) { + int x = cur[0], y = cur[1]; + // 和其他题目不同的是,这里一直走到墙,而不是只走一步 + while (x >= 0 && x < m && y >= 0 && y < n && maze[x][y] == 0) { + x += dir[0]; + y += dir[1]; + } + x -= dir[0]; + y -= dir[1]; + // 判断是否到达终点 + if (x == destination[0] && y == destination[1]) { + return true; + } + if (!visited[x][y]) { + visited[x][y] = true; + q.offer(new int[]{x, y}); + } + } + } + return false; + } +} +``` + +```javascript +// by chatGPT (javascript) +var hasPath = function(maze, start, destination) { + var m = maze.length, n = maze[0].length; + // 方向数组,方便上下左右移动 + var dirs = [[0,1],[0,-1],[1,0],[-1,0]]; + + // BFS 算法的队列和 visited 数组 + var q = []; + var visited = new Array(m); + for (var i = 0; i < m; i++) { + visited[i] = new Array(n).fill(false); + } + // 加入起点 + q.push(start); + visited[start[0]][start[1]] = true; + // 启动 BFS 算法框架 + while (q.length > 0) { + var cur = q.shift(); + // 向四个方向扩展 + for (var i = 0; i < 4; i++) { + var dir = dirs[i]; + var x = cur[0], y = cur[1]; + // 和其他题目不同的是,这里一直走到墙,而不是只走一步 + while (x >= 0 && x < m && y >= 0 && y < n && maze[x][y] == 0) { + x += dir[0]; + y += dir[1]; + } + x -= dir[0]; + y -= dir[1]; + // 判断是否到达终点 + if (x == destination[0] && y == destination[1]) { + return true; + } + if (!visited[x][y]) { + visited[x][y] = true; + q.push([x, y]); + } + } + } + return false; +}; +``` + +```python +# by chatGPT (python) +from typing import List +from queue import Queue + +class Solution: + def hasPath(self, maze: List[List[int]], start: List[int], destination: List[int]) -> bool: + m, n = len(maze), len(maze[0]) # 获取矩阵的行和列 + dirs = [(0, 1), (0, -1), (1, 0), (-1, 0)] # 四个方向 + + q = Queue() # BFS 算法的队列 + visited = [[False for _ in range(n)] for _ in range(m)] # visited 数组 + q.put(start) # 加入起点 + visited[start[0]][start[1]] = True # 设置该点已访问 + # 启动 BFS 算法框架 + while not q.empty(): + x, y = q.get() + # 向四个方向扩展 + for dir in dirs: + # 和其他题目不同的是,这里一直走到墙,而不是只走一步 + nr, nc = x, y + while 0 <= nr < m and 0 <= nc < n and not maze[nr][nc]: + nr += dir[0] + nc += dir[1] + nr -= dir[0] # 走过墙后需要回退一步 + nc -= dir[1] + # 判断是否到达终点 + if (nr, nc) == tuple(destination): + return True + if not visited[nr][nc]: + visited[nr][nc] = True # 设置该点已访问 + q.put((nr, nc)) + + return False +``` + +https://leetcode.cn/problems/the-maze 的多语言解法👆 + +https://leetcode.cn/problems/the-maze-ii 的多语言解法👇 + +```cpp +// by chatGPT (cpp) +class Solution { +public: + int shortestDistance(vector>& maze, vector& start, vector& destination) { + int m = maze.size(), n = maze[0].size(); + // 方向数组,方便上下左右移动 + vector> dirs = {{0, 1}, {0, -1}, {1, 0}, {-1, 0}}; + + // BFS 算法的队列和 visited 数组 + queue> q; + vector> visited(m, vector(n, false)); + // 加入起点 + q.push(start); + visited[start[0]][start[1]] = true; + // 启动 BFS 算法框架 + while (!q.empty()) { + vector cur = q.front(); + q.pop(); + // 向四个方向扩展 + for (auto dir : dirs) { + int x = cur[0], y = cur[1]; + int step = 0; + // 和其他题目不同的是,这里一直走到墙,而不是只走一步,同时要记录走过的步数 + while (x >= 0 && x < m && y >= 0 && y < n && maze[x][y] == 0) { + x += dir[0]; + y += dir[1]; + step++; + } + x -= dir[0]; + y -= dir[1]; + step--; + // 判断是否到达终点 + if (x == destination[0] && y == destination[1]) { + return step; + } + if (!visited[x][y]) { + visited[x][y] = true; + q.push({x, y}); + } + } + } + return -1; + } +}; +``` + +```go +// by chatGPT (go) +import "container/list" + +func shortestDistance(maze [][]int, start []int, destination []int) int { + m, n := len(maze), len(maze[0]) + // 方向数组,方便上下左右移动 + dirs := [][]int{{0,1},{0,-1},{1,0},{-1,0}} + + // BFS 算法的队列和 visited 数组 + q := list.New() + visited := make([][]bool, m) + for i := range visited { + visited[i] = make([]bool, n) + } + // 加入起点 + q.PushBack(start) + visited[start[0]][start[1]] = true + // 启动 BFS 算法框架 + for q.Len() != 0 { + cur := q.Front().Value.([]int) + q.Remove(q.Front()) + // 向四个方向扩展 + for _, dir := range dirs { + x, y := cur[0], cur[1] + step := 0 + // 和其他题目不同的是,这里一直走到墙,而不是只走一步,同时要记录走过的步数 + for x >= 0 && x < m && y >= 0 && y < n && maze[x][y] == 0 { + x += dir[0] + y += dir[1] + step++ + } + x -= dir[0] + y -= dir[1] + step-- + // 判断是否到达终点 + if x == destination[0] && y == destination[1] { + return step + } + if !visited[x][y] { + visited[x][y] = true + q.PushBack([]int{x, y}) + } + } + } + return -1 +} +``` + +```java +// by labuladong (java) +class Solution { + public int shortestDistance(int[][] maze, int[] start, int[] destination) { + int m = maze.length, n = maze[0].length; + // 方向数组,方便上下左右移动 + int[][] dirs = {{0,1},{0,-1},{1,0},{-1,0}}; + + // BFS 算法的队列和 visited 数组 + Queue q = new LinkedList<>(); + boolean[][] visited = new boolean[m][n]; + // 加入起点 + q.offer(start); + visited[start[0]][start[1]] = true; + // 启动 BFS 算法框架 + while (!q.isEmpty()) { + int[] cur = q.poll(); + // 向四个方向扩展 + for (int[] dir : dirs) { + int x = cur[0], y = cur[1]; + int step = 0; + // 和其他题目不同的是,这里一直走到墙,而不是只走一步,同时要记录走过的步数 + while (x >= 0 && x < m && y >= 0 && y < n && maze[x][y] == 0) { + x += dir[0]; + y += dir[1]; + step++; + } + x -= dir[0]; + y -= dir[1]; + step--; + // 判断是否到达终点 + if (x == destination[0] && y == destination[1]) { + return step; + } + if (!visited[x][y]) { + visited[x][y] = true; + q.offer(new int[]{x, y}); + } + } + } + return -1; + } +} +``` + +```javascript +// by chatGPT (javascript) +var shortestDistance = function(maze, start, destination) { + var m = maze.length, n = maze[0].length; + // 方向数组,方便上下左右移动 + var dirs = [[0,1],[0,-1],[1,0],[-1,0]]; + + // BFS 算法的队列和 visited 数组 + var q = []; + var visited = new Array(m); + for (var i = 0; i < m; i++) { + visited[i] = new Array(n).fill(false); + } + // 加入起点 + q.push(start); + visited[start[0]][start[1]] = true; + // 启动 BFS 算法框架 + while (q.length > 0) { + var cur = q.shift(); + // 向四个方向扩展 + for (var dir of dirs) { + var x = cur[0], y = cur[1]; + var step = 0; + // 和其他题目不同的是,这里一直走到墙,而不是只走一步,同时要记录走过的步数 + while (x >= 0 && x < m && y >= 0 && y < n && maze[x][y] == 0) { + x += dir[0]; + y += dir[1]; + step++; + } + x -= dir[0]; + y -= dir[1]; + step--; + // 判断是否到达终点 + if (x == destination[0] && y == destination[1]) { + return step; + } + if (!visited[x][y]) { + visited[x][y] = true; + q.push([x, y]); + } + } + } + return -1; +}; +``` + +```python +# by chatGPT (python) +from queue import Queue + +class Solution: + def shortestDistance(self, maze: List[List[int]], start: List[int], destination: List[int]) -> int: + m, n = len(maze), len(maze[0]) + + # 方向数组,方便上下左右移动 + dirs = [(0,1), (0,-1), (1,0), (-1,0)] + + # BFS 算法的队列和 visited 数组 + q = Queue() + visited = [[False for _ in range(n)] for _ in range(m)] + # 加入起点 + q.put(start) + visited[start[0]][start[1]] = True + # 启动 BFS 算法框架 + while not q.empty(): + cur = q.get() + # 向四个方向扩展 + for dir in dirs: + x, y = cur[0], cur[1] + step = 0 + # 和其他题目不同的是,这里一直走到墙,而不是只走一步,同时要记录走过的步数 + while x >= 0 and x < m and y >= 0 and y < n and maze[x][y] == 0: + x += dir[0] + y += dir[1] + step += 1 + x -= dir[0] + y -= dir[1] + step -= 1 + # 判断是否到达终点 + if x == destination[0] and y == destination[1]: + return step + if not visited[x][y]: + visited[x][y] = True + q.put((x, y)) + return -1 +``` + +https://leetcode.cn/problems/the-maze-ii 的多语言解法👆 + https://leetcode.cn/problems/ti-huan-kong-ge-lcof 的多语言解法👇 ```cpp @@ -70109,4 +71018,4 @@ class Solution: return s[n:] + s[:n] ``` -https://leetcode.cn/problems/zuo-xuan-zhuan-zi-fu-chuan-lcof 的多语言解法👆 +https://leetcode.cn/problems/zuo-xuan-zhuan-zi-fu-chuan-lcof 的多语言解法👆 \ No newline at end of file diff --git "a/\347\256\227\346\263\225\346\200\235\347\273\264\347\263\273\345\210\227/\344\272\214\345\210\206\346\237\245\346\211\276\350\257\246\350\247\243.md" "b/\347\256\227\346\263\225\346\200\235\347\273\264\347\263\273\345\210\227/\344\272\214\345\210\206\346\237\245\346\211\276\350\257\246\350\247\243.md" index 47533170d5..1238b72aa1 100644 --- "a/\347\256\227\346\263\225\346\200\235\347\273\264\347\263\273\345\210\227/\344\272\214\345\210\206\346\237\245\346\211\276\350\257\246\350\247\243.md" +++ "b/\347\256\227\346\263\225\346\200\235\347\273\264\347\263\273\345\210\227/\344\272\214\345\210\206\346\237\245\346\211\276\350\257\246\350\247\243.md" @@ -185,22 +185,22 @@ int left_bound(int[] nums, int target) { **2、为什么没有返回 -1 的操作?如果 `nums` 中不存在 `target` 这个值,怎么办**? -答:其实很简单,在返回的时候额外判断一下 `nums[left]` 是否等于 `target` 就行了,如果不等于,就说明 `target` 不存在。 - -不过我们得考察一下 `left` 的取值范围,免得索引越界。假如输入的 `target` 非常大,那么就会一直触发 `nums[mid] < target` 的 if 条件,`left` 会一直向右侧移动,直到等于 `right`,while 循环结束。 - -由于这里 `right` 初始化为 `nums.length`,所以 `left` 变量的取值区间是闭区间 `[0, nums.length]`,那么我们在检查 `nums[left]` 之前需要额外判断一下,防止索引越界: +答:其实很简单,在返回的时候额外判断一下 `nums[left]` 是否等于 `target` 就行了,如果不等于,就说明 `target` 不存在。需要注意的是,访问数组索引之前要保证索引不越界: ```java while (left < right) { //... } -// 此时 target 比所有数都大,返回 -1 -if (left == nums.length) return -1; +// 如果索引越界,说明数组中无目标元素,返回 -1 +if (left < 0 || left >= nums.length) { + return -1; +} // 判断一下 nums[left] 是不是 target return nums[left] == target ? left : -1; ``` +> tip:其实对于这个算法,`left` 不可能小于 0。你可以想象一下算法执行的逻辑,left 初始化就是 0,且只可能一直往右走,那么只可能在右侧越界。不过在访问数组索引之前保证索引在左右两端都不越界是一个很好的编程习惯,没有坏处,我这里就同时判断了。这样做的另一个好处是可以让二分的模板更统一,降低你的记忆成本。 + **3、为什么 `left = mid + 1`,`right = mid` ?和之前的算法不一样**? 答:这个很好解释,因为我们的「搜索区间」是 `[left, right)` 左闭右开,所以当 `nums[mid]` 被检测之后,下一步应该去 `mid` 的左侧或者右侧区间搜索,即 `[left, mid)` 或 `[mid + 1, right)`。 @@ -284,8 +284,10 @@ int left_bound(int[] nums, int target) { } } // 判断 target 是否存在于 nums 中 - // 此时 target 比所有数都大,返回 -1 - if (left == nums.length) return -1; + // 如果越界,target 肯定不存在,返回 -1 + if (left < 0 || left >= nums.length) { + return -1; + } // 判断一下 nums[left] 是不是 target return nums[left] == target ? left : -1; } @@ -350,9 +352,7 @@ if (nums[mid] == target) { **3、为什么没有返回 -1 的操作?如果 `nums` 中不存在 `target` 这个值,怎么办**? -答:只要在最后判断一下 `nums[left-1]` 是不是 `target` 就行了。 - -类似之前的左侧边界搜索,`left` 的取值范围是 `[0, nums.length]`,但由于我们最后返回的是 `left - 1`,所以 `left` 取值为 0 的时候会造成索引越界,额外处理一下即可正确地返回 -1: +答:只要在最后判断一下 `nums[left-1]` 是不是 `target` 就行了,类似之前的左侧边界搜索,做一点额外的判断即可: ```java @@ -360,9 +360,11 @@ while (left < right) { // ... } // 判断 target 是否存在于 nums 中 -// 此时 left - 1 索引越界 -if (left - 1 < 0) return -1; -// 判断一下 nums[left] 是不是 target +// left - 1 索引越界的话 target 肯定不存在 +if (left - 1 < 0 || left - 1 >= nums.length) { + return -1; +} +// 判断一下 nums[left - 1] 是不是 target return nums[left - 1] == target ? (left - 1) : -1; ``` @@ -386,22 +388,44 @@ int right_bound(int[] nums, int target) { } } // 最后改成返回 left - 1 - if (left - 1 < 0) return -1; + if (left - 1 < 0 || left - 1 >= nums.length) { + return -1; + } return nums[left - 1] == target ? (left - 1) : -1; } ``` -当然,由于 while 的结束条件为 `right == left - 1`,所以你把上述代码中的 `left - 1` 都改成 `right` 也没有问题,这样可能更有利于看出来这是在「搜索右侧边界」。 +当然,由于 while 的结束条件为 `right == left - 1`,所以你把上述代码中的 `left - 1` 都改成 `right` 也没有问题,这样可能更有利于看出来这是在「搜索右侧边界」: + +```java +int right_bound(int[] nums, int target) { + int left = 0, right = nums.length - 1; + while (left <= right) { + int mid = left + (right - left) / 2; + if (nums[mid] < target) { + left = mid + 1; + } else if (nums[mid] > target) { + right = mid - 1; + } else if (nums[mid] == target) { + // 这里改成收缩左侧边界即可 + left = mid + 1; + } + } + // 最后改成返回 right + if (right < 0 || right >= nums.length) { + return -1; + } + return nums[right] == target ? right : -1; +} +``` 至此,搜索右侧边界的二分查找的两种写法也完成了,其实将「搜索区间」统一成两端都闭反而更容易记忆,你说是吧? ### 四、逻辑统一 -有了搜索左右边界的二分搜索,你可以去解决力扣第 34 题「在排序数组中查找元素的第一个和最后一个位置」, - -接下来梳理一下这些细节差异的因果逻辑: +有了搜索左右边界的二分搜索,你可以去解决力扣第 34 题「在排序数组中查找元素的第一个和最后一个位置」。接下来梳理一下这些细节差异的因果逻辑: **第一个,最基本的二分查找算法**: @@ -444,7 +468,7 @@ int right_bound(int[] nums, int target) { 所以最后无论返回 left 还是 right,必须减一 ``` -对于寻找左右边界的二分搜索,常见的手法是使用左闭右开的「搜索区间」,**我们还根据逻辑将「搜索区间」全都统一成了两端都闭,便于记忆,只要修改两处即可变化出三种写法**: +对于寻找左右边界的二分搜索,比较常见的手法是使用左闭右开的「搜索区间」,**我们还根据逻辑将「搜索区间」全都统一成了两端都闭,便于记忆,只要修改两处即可变化出三种写法**: ```java @@ -479,8 +503,9 @@ int left_bound(int[] nums, int target) { } } // 判断 target 是否存在于 nums 中 - // 此时 target 比所有数都大,返回 -1 - if (left == nums.length) return -1; + if (left < 0 || left >= nums.length) { + return -1; + } // 判断一下 nums[left] 是不是 target return nums[left] == target ? left : -1; } @@ -499,12 +524,15 @@ int right_bound(int[] nums, int target) { } } // 判断 target 是否存在于 nums 中 - // if (left - 1 < 0) return -1; - // return nums[left - 1] == target ? (left - 1) : -1; + // if (left - 1 < 0 || left - 1 >= nums.length) { + // return -1; + // } // 由于 while 的结束条件是 right == left - 1,且现在在求右边界 // 所以用 right 替代 left - 1 更好记 - if (right < 0) return -1; + if (right < 0 || right >= nums.length) { + return -1; + } return nums[right] == target ? right : -1; } ``` diff --git "a/\347\256\227\346\263\225\346\200\235\347\273\264\347\263\273\345\210\227/\345\233\236\346\272\257\347\256\227\346\263\225\350\257\246\350\247\243\344\277\256\350\256\242\347\211\210.md" "b/\347\256\227\346\263\225\346\200\235\347\273\264\347\263\273\345\210\227/\345\233\236\346\272\257\347\256\227\346\263\225\350\257\246\350\247\243\344\277\256\350\256\242\347\211\210.md" index a403562092..863789ff69 100644 --- "a/\347\256\227\346\263\225\346\200\235\347\273\264\347\263\273\345\210\227/\345\233\236\346\272\257\347\256\227\346\263\225\350\257\246\350\247\243\344\277\256\350\256\242\347\211\210.md" +++ "b/\347\256\227\346\263\225\346\200\235\347\273\264\347\263\273\345\210\227/\345\233\236\346\272\257\347\256\227\346\263\225\350\257\246\350\247\243\344\277\256\350\256\242\347\211\210.md" @@ -35,7 +35,7 @@ tags: ['回溯算法', '核心框架'] 回溯算法是什么?解决回溯算法相关的问题有什么技巧?如何学习回溯算法?回溯算法代码是否有规律可循? -其实回溯算法和我们常说的 DFS 算法非常类似,本质上就是一种暴力穷举算法。回溯算法和 DFS 算法的细微差别是:**回溯算法是在遍历「树枝」,DFS 算法是在遍历「节点」**,本文就是简单提一下,等你看到后文 [图论算法基础](https://labuladong.github.io/article/fname.html?fname=图) 时就能深刻理解这句话的含义了。 +其实回溯算法和我们常说的 DFS 算法非常类似,本质上就是一种暴力穷举算法。回溯算法和 DFS 算法的细微差别是:**回溯算法是在遍历「树枝」,DFS 算法是在遍历「节点」**,本文就是简单提一下,你有个印象就行了。等你看了 [手把手刷二叉树(纲领篇)](https://labuladong.github.io/article/fname.html?fname=二叉树总结) 和 [图论算法基础](https://labuladong.github.io/article/fname.html?fname=图) 之后就能深刻理解这句话的含义了。 废话不多说,直接上回溯算法框架,解决一个回溯问题,实际上就是一个决策树的遍历过程,站在回溯树的一个节点上,你只需要思考 3 个问题: diff --git "a/\347\256\227\346\263\225\346\200\235\347\273\264\347\263\273\345\210\227/\346\273\221\345\212\250\347\252\227\345\217\243\346\212\200\345\267\247\350\277\233\351\230\266.md" "b/\347\256\227\346\263\225\346\200\235\347\273\264\347\263\273\345\210\227/\346\273\221\345\212\250\347\252\227\345\217\243\346\212\200\345\267\247\350\277\233\351\230\266.md" index 5000614eb3..f142b1a9db 100644 --- "a/\347\256\227\346\263\225\346\200\235\347\273\264\347\263\273\345\210\227/\346\273\221\345\212\250\347\252\227\345\217\243\346\212\200\345\267\247\350\277\233\351\230\266.md" +++ "b/\347\256\227\346\263\225\346\200\235\347\273\264\347\263\273\345\210\227/\346\273\221\345\212\250\347\252\227\345\217\243\346\212\200\345\267\247\350\277\233\351\230\266.md" @@ -77,7 +77,7 @@ void slidingWindow(string s) { while (right < s.size()) { // c 是将移入窗口的字符 char c = s[right]; - winodw.add(c) + window.add(c) // 增大窗口 right++; // 进行窗口内数据的一系列更新 @@ -93,7 +93,7 @@ void slidingWindow(string s) { while (left < right && window needs shrink) { // d 是将移出窗口的字符 char d = s[left]; - winodw.remove(d) + window.remove(d) // 缩小窗口 left++; // 进行窗口内数据的一系列更新