From 7fe41c8f8c788d83714d7134a7a0bd366143fbf0 Mon Sep 17 00:00:00 2001 From: ITCharge Date: Mon, 5 Sep 2022 16:10:58 +0800 Subject: [PATCH 01/10] =?UTF-8?q?Update=200130.=20=E8=A2=AB=E5=9B=B4?= =?UTF-8?q?=E7=BB=95=E7=9A=84=E5=8C=BA=E5=9F=9F.md?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...25347円232円204円345円214円272円345円237円237円.md" | 33 ++++++++++++++++--- 1 file changed, 28 insertions(+), 5 deletions(-) diff --git "a/Solutions/0130. 350円242円253円345円233円264円347円273円225円347円232円204円345円214円272円345円237円237円.md" "b/Solutions/0130. 350円242円253円345円233円264円347円273円225円347円232円204円345円214円272円345円237円237円.md" index fbb09dfa..be89099b 100644 --- "a/Solutions/0130. 350円242円253円345円233円264円347円273円225円347円232円204円345円214円272円345円237円237円.md" +++ "b/Solutions/0130. 350円242円253円345円233円264円347円273円225円347円232円204円345円214円272円345円237円237円.md" @@ -5,15 +5,34 @@ ## 题目大意 -给定一个 `m * n` 的矩阵 `board`,由若干字符 `X` 和 `O` 构成。 +**描述**:给定一个 `m * n` 的矩阵 `board`,由若干字符 `X` 和 `O` 构成。 -要求:找到所有被 `X` 围绕的区域,并将这些区域里所有的 `O` 用 `X` 填充。 +**要求**:找到所有被 `X` 围绕的区域,并将这些区域里所有的 `O` 用 `X` 填充。 -注意:被围绕的区间不会存在于边界上,换句话说,任何边界上的 `O` 都不会被填充为 `X`。 任何不在边界上,或不与边界上的 `O` 相连的 `O` 最终都会被填充为 `X`。如果两个元素在水平或垂直方向相邻,则称它们是相连的。 +**说明**: + +- $m == board.length$。 +- $n == board[i].length$。 +- 1ドル <= m, n <= 200$。 +- $board[i][j]$ 为 `'X'` 或 `'O'`。 + +**示例**: + +![](https://assets.leetcode.com/uploads/2021/02/19/xogrid.jpg) + +```Python +输入:board = [["X","X","X","X"],["X","O","O","X"],["X","X","O","X"],["X","O","X","X"]] +输出:[["X","X","X","X"],["X","X","X","X"],["X","X","X","X"],["X","O","X","X"]] +解释:被围绕的区间不会存在于边界上,换句话说,任何边界上的 'O' 都不会被填充为 'X'。 任何不在边界上,或不与边界上的 'O' 相连的 'O' 最终都会被填充为 'X'。如果两个元素在水平或垂直方向相邻,则称它们是"相连"的。 + + +输入:board = [["X"]] +输出:[["X"]] +``` ## 解题思路 -深度优先搜索求解。 +### 思路 1:深度优先搜索 根据题意,任何边界上的 `O` 都不会被填充为`X`。而被填充 `X` 的 `O` 一定在内部不在边界上。 @@ -21,7 +40,7 @@ 最后遍历一遍 `board`,将所有 `#` 变换为 `O`,将所有 `O` 变换为 `X`。 -## 代码 +### 思路 1:代码 ```Python class Solution: @@ -58,3 +77,7 @@ class Solution: board[i][j] = 'X' ``` +### 思路 1:复杂度分析 + +- **时间复杂度**:$O(n \times m),ドル其中 $m$ 和 $n$ 分别为行数和列数。 +- **空间复杂度**:$O(n \times m)$。 \ No newline at end of file From 0a35bb2ba27fc1ef93b277ee8ab83267e4f38ed1 Mon Sep 17 00:00:00 2001 From: ITCharge Date: Mon, 5 Sep 2022 16:11:00 +0800 Subject: [PATCH 02/10] =?UTF-8?q?Update=200133.=20=E5=85=8B=E9=9A=86?= =?UTF-8?q?=E5=9B=BE.md?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .... 345円205円213円351円232円206円345円233円276円.md" | 50 +++++++++++++++++-- 1 file changed, 46 insertions(+), 4 deletions(-) diff --git "a/Solutions/0133. 345円205円213円351円232円206円345円233円276円.md" "b/Solutions/0133. 345円205円213円351円232円206円345円233円276円.md" index d47f2dfc..9afa14a7 100644 --- "a/Solutions/0133. 345円205円213円351円232円206円345円233円276円.md" +++ "b/Solutions/0133. 345円205円213円351円232円206円345円233円276円.md" @@ -5,9 +5,39 @@ ## 题目大意 -给定一个无向连通图中一个节点的引用。 +**描述**:以每个节点的邻接列表形式(二维列表)给定一个无向连通图,其中 `adjList[i]` 表示值为 `i + 1`的节点的邻接列表,`adjList[i][j]` 表示值为 `i + 1` 的节点与值为 `adjList[i][j]` 的节点有一条边。 -要求:返回该图的深拷贝。 +**要求**:返回该图的深拷贝。 + +**说明**: + +- 节点数不超过 `100`。 +- 每个节点值 $Node.val$ 都是唯一的,1ドル \le Node.val \le 100$。 +- 无向图是一个简单图,这意味着图中没有重复的边,也没有自环。 +- 由于图是无向的,如果节点 `p` 是节点 `q` 的邻居,那么节点 `q` 也必须是节点 `p` 的邻居。 +- 图是连通图,你可以从给定节点访问到所有节点。 + +**示例**: + +![](https://assets.leetcode-cn.com/aliyun-lc-upload/uploads/2020/02/01/133_clone_graph_question.png) + +```Python +输入:adjList = [[2,4],[1,3],[2,4],[1,3]] +输出:[[2,4],[1,3],[2,4],[1,3]] +解释: +图中有 4 个节点。 +节点 1 的值是 1,它有两个邻居:节点 2 和 4 。 +节点 2 的值是 2,它有两个邻居:节点 1 和 3 。 +节点 3 的值是 3,它有两个邻居:节点 2 和 4 。 +节点 4 的值是 4,它有两个邻居:节点 1 和 3 。 +``` + +![](https://assets.leetcode-cn.com/aliyun-lc-upload/uploads/2020/02/01/graph-1.png) + +```Python +输入:adjList = [[2],[1]] +输出:[[2],[1]] +``` ## 解题思路 @@ -15,9 +45,16 @@ 可以用深度优先搜索或者广度优先搜索来做。 -以深度优先搜索为例,根据所给定的节点,以深度优先搜索的方式遍历图,并在遍历图的同时,进行新建节点,并构建新图。 +### 思路 1:深度优先搜索 -## 代码 +1. 使用哈希表 `visitedDict` 来存储原图中被访问过的节点和克隆图中对应节点,键值对为 原图被访问过的节点:克隆图中对应节点。 +2. 从给定节点开始,以深度优先搜索的方式遍历原图。 + 1. 如果当前节点被访问过,则返回隆图中对应节点。 + 2. 如果当前节点没有被访问过,则创建一个新的节点,并保存在哈希表中。 + 3. 遍历当前节点的邻接节点列表,递归调用当前节点的邻接节点,并将其放入克隆图中对应节点。 +3. 递归结束,返回克隆节点。 + +### 思路 1:代码 ```Python class Solution: @@ -39,3 +76,8 @@ class Solution: return dfs(node) ``` +### 思路 1:复杂度分析 + +- **时间复杂度**:$O(n)$。其中 $n$ 为图中节点数量。 +- **空间复杂度**:$O(n)$。 + From 65b89c52735f6e071afc84a06b3eed8b358d2a82 Mon Sep 17 00:00:00 2001 From: ITCharge Date: Mon, 5 Sep 2022 16:11:01 +0800 Subject: [PATCH 03/10] =?UTF-8?q?Update=200200.=20=E5=B2=9B=E5=B1=BF?= =?UTF-8?q?=E6=95=B0=E9=87=8F.md?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...33345円261円277円346円225円260円351円207円217円.md" | 57 +++++++++++++++---- 1 file changed, 47 insertions(+), 10 deletions(-) diff --git "a/Solutions/0200. 345円262円233円345円261円277円346円225円260円351円207円217円.md" "b/Solutions/0200. 345円262円233円345円261円277円346円225円260円351円207円217円.md" index 3fec8ba8..0fb20666 100644 --- "a/Solutions/0200. 345円262円233円345円261円277円346円225円260円351円207円217円.md" +++ "b/Solutions/0200. 345円262円233円345円261円277円346円225円260円351円207円217円.md" @@ -5,23 +5,55 @@ ## 题目大意 -给你一个由 '1'(陆地)和 '0'(水)组成的的二维网格 `grid`。 +**描述**:给定一个由字符 `'1'`(陆地)和字符 `'0'`(水)组成的的二维网格 `grid`。 -要求:计算网格中岛屿的数量。 +**要求**:计算网格中岛屿的数量。 -- 岛屿总是被水包围,并且每座岛屿只能由水平方向和/或竖直方向上相邻的陆地连接形成。 +**说明**: +- 岛屿总是被水包围,并且每座岛屿只能由水平方向和/或竖直方向上相邻的陆地连接形成。 - 此外,你可以假设该网格的四条边均被水包围。 +- $m == grid.length$。 +- $n == grid[i].length$。 +- 1ドル \le m, n \le 300$。 +- `grid[i][j]` 的值为 `'0'` 或 `'1'`。 + +**示例**: + +```Python +输入:grid = [ + ["1","1","1","1","0"], + ["1","1","0","1","0"], + ["1","1","0","0","0"], + ["0","0","0","0","0"] +] +输出:1 + + +输入:grid = [ + ["1","1","0","0","0"], + ["1","1","0","0","0"], + ["0","0","1","0","0"], + ["0","0","0","1","1"] +] +输出:3 +``` ## 解题思路 -如果把上下左右相邻的字符 '1' 看做是 1 个连通块,这道题的目的就是求解一共有多少个连通块。 +如果把上下左右相邻的字符 `'1'` 看做是 `1` 个连通块,这道题的目的就是求解一共有多少个连通块。 使用深度优先搜索或者广度优先搜索都可以。 -以深度优先搜索为例。遍历 `grid` 。对于每一个字符为 '1' 的元素,遍历其上下左右四个方向,并将该字符置为 `0`,保证下次不会被重复遍历。对于 `(i, j)` 位置的元素来说,递归遍历的位置就是 `(i - 1, j)`、`(i, j - 1)`、`(i + 1, j)`、`(i, j + 1)` 四个方向。每次遍历到底,统计数记录一次。最终统计出深度优先搜索的次数就是我们要求的岛屿数量。 +### 思路 1:深度优先搜索 + +1. 遍历 `grid` 。 +2. 对于每一个字符为 `'1'` 的元素,遍历其上下左右四个方向,并将该字符置为 `0`,保证下次不会被重复遍历。 +3. 如果超出边界,则返回 `0`。 +4. 对于 `(i, j)` 位置的元素来说,递归遍历的位置就是 `(i - 1, j)`、`(i, j - 1)`、`(i + 1, j)`、`(i, j + 1)` 四个方向。每次遍历到底,统计数记录一次。 +5. 最终统计出深度优先搜索的次数就是我们要求的岛屿数量。 -## 代码 +### 思路 1:代码 ```Python class Solution: @@ -31,10 +63,10 @@ class Solution: if i < 0 or i>= n or j < 0 or j>= m or grid[i][j] == '0': return 0 grid[i][j] = '0' - self.dfs(grid, i+1, j) - self.dfs(grid, i, j+1) - self.dfs(grid, i-1, j) - self.dfs(grid, i, j-1) + self.dfs(grid, i + 1, j) + self.dfs(grid, i, j + 1) + self.dfs(grid, i - 1, j) + self.dfs(grid, i, j - 1) def numIslands(self, grid: List[List[str]]) -> int: count = 0 @@ -46,3 +78,8 @@ class Solution: return count ``` +### 思路 1:复杂度分析 + +- **时间复杂度**:$O(m \times n)$。其中 $m$ 和 $n$ 分别为行数和列数。 +- **空间复杂度**:$O(m \times n)$。 + From f5c6502699fc7bfc9bf7ea825152a5b609a9ca8b Mon Sep 17 00:00:00 2001 From: ITCharge Date: Mon, 5 Sep 2022 16:11:03 +0800 Subject: [PATCH 04/10] =?UTF-8?q?Update=200417.=20=E5=A4=AA=E5=B9=B3?= =?UTF-8?q?=E6=B4=8B=E5=A4=A7=E8=A5=BF=E6=B4=8B=E6=B0=B4=E6=B5=81=E9=97=AE?= =?UTF-8?q?=E9=A2=98.md?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...264円213円346円260円264円346円265円201円351円227円256円351円242円230円.md" | 2 ++ 1 file changed, 2 insertions(+) diff --git "a/Solutions/0417. 345円244円252円345円271円263円346円264円213円345円244円247円350円245円277円346円264円213円346円260円264円346円265円201円351円227円256円351円242円230円.md" "b/Solutions/0417. 345円244円252円345円271円263円346円264円213円345円244円247円350円245円277円346円264円213円346円260円264円346円265円201円351円227円256円351円242円230円.md" index c0470388..c407c79c 100644 --- "a/Solutions/0417. 345円244円252円345円271円263円346円264円213円345円244円247円350円245円277円346円264円213円346円260円264円346円265円201円351円227円256円351円242円230円.md" +++ "b/Solutions/0417. 345円244円252円345円271円263円346円264円213円345円244円247円350円245円277円346円264円213円346円260円264円346円265円201円351円227円256円351円242円230円.md" @@ -5,6 +5,8 @@ ## 题目大意 + + 给定一个 `m * n` 大小的二维非负整数矩阵 `heights` 来表示一片大陆上各个单元格的高度。`heights[i][j]` 表示第 `i` 行第 `j` 列所代表的陆地高度。这个二维矩阵所代表的陆地被太平洋和大西洋所包围着。左上角是「太平洋」,右下角是「大西洋」。规定水流只能按照上、下、左、右四个方向流动,且只能从高处流到低处,或者在同等高度上流动。 要求:找出代表陆地的二维矩阵中,水流既可以从该处流动到太平洋,又可以流动到大西洋的所有坐标。 From 6d6f019467d877b89c7f629dc60bedf8923b04a6 Mon Sep 17 00:00:00 2001 From: ITCharge Date: Mon, 5 Sep 2022 16:11:05 +0800 Subject: [PATCH 05/10] =?UTF-8?q?Update=200494.=20=E7=9B=AE=E6=A0=87?= =?UTF-8?q?=E5=92=8C.md?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .... 347円233円256円346円240円207円345円222円214円.md" | 144 +++++++++++++++++- 1 file changed, 138 insertions(+), 6 deletions(-) diff --git "a/Solutions/0494. 347円233円256円346円240円207円345円222円214円.md" "b/Solutions/0494. 347円233円256円346円240円207円345円222円214円.md" index 82af3eb5..a64fa7b2 100644 --- "a/Solutions/0494. 347円233円256円346円240円207円345円222円214円.md" +++ "b/Solutions/0494. 347円233円256円346円240円207円345円222円214円.md" @@ -5,13 +5,123 @@ ## 题目大意 -给定一个整数数组 `nums` 和一个整数 `target`。数组长度不超过 20。向数组中每个整数前加 `+` 或 `-`。然后串联起来构造成一个表达式。 +**描述**:给定一个整数数组 `nums` 和一个整数 `target`。数组长度不超过 `20`。向数组中每个整数前加 `+` 或 `-`。然后串联起来构造成一个表达式。 -要求:返回通过上述方法构造的、运算结果等于 `target` 的不同表达式数目。 +**要求**:返回通过上述方法构造的、运算结果等于 `target` 的不同表达式数目。 + +**说明**: + +- 1ドル \le nums.length \le 20$。 +- 0ドル \le nums[i] \le 1000$。 +- 0ドル \le sum(nums[i]) \le 1000$。 +- $-1000 \le target \le 1000$。 + +**示例**: + +```Python +输入:nums = [1,1,1,1,1], target = 3 +输出:5 +解释:一共有 5 种方法让最终目标和为 3。 +-1 +たす 1 +たす 1 +たす 1 +たす 1 = 3 +たす+たす1 -ひく 1 +たす 1 +たす 1 +たす 1 = 3 +たす+たす1 +たす 1 -ひく 1 +たす 1 +たす 1 = 3 +たす+たす1 +たす 1 +たす 1 -ひく 1 +たす 1 = 3 +たす+たす1 +たす 1 +たす 1 +たす 1 -ひく 1 = 3 + + +输入:nums = [1], target = 1 +输出:1 +``` ## 解题思路 -暴力方法就是使用深度优先搜索对每位数字遍历 `+`、`-`,并统计符合要求的表达式数目。但是实际发现超时了。所以采用动态规划的方法来做。 +### 思路 1:深度优先搜索(超时) + +使用深度优先搜索对每位数字进行 `+` 或者 `-`,具体步骤如下: + +1. 定义从位置 `0`、和为 `0` 开始,到达数组尾部位置为止,和为 `target` 的方案数为 `dfs(0, 0)`,`size`。 +2. 下面从位置 `0`、和为 `0` 开始,以深度优先搜索遍历每个位置。 +3. 如果当前位置 `i` 到达最后一个位置 `size`: + 1. 如果和 `cur_sum` 等于目标和 `target`,则返回方案数 `1`。 + 2. 如果和 `cur_sum` 不等于目标和 `target`,则返回方案数 `0`。 +4. 递归搜索 `i + 1` 位置,和为 `cur_sum - nums[i]` 的方案数。 +5. 递归搜索 `i + 1` 位置,和为 `cur_sum + nums[i]` 的方案数。 +6. 将 4 ~ 5 两个方案数加起来就是当前位置 `i`、和为 `cur_sum` 的方案数,返回该方案数。 +7. 最终方案数为 `dfs(0, 0)`,将其作为答案返回即可。 + +### 思路 1:代码 + +```Python +class Solution: + def findTargetSumWays(self, nums: List[int], target: int) -> int: + size = len(nums) + + def dfs(i, cur_sum): + if i == size: + if cur_sum == target: + return 1 + else: + return 0 + ans = dfs(i + 1, cur_sum - nums[i]) + dfs(i + 1, cur_sum + nums[i]) + return ans + + return dfs(0, 0) +``` + +### 思路 1:复杂度分析 + +- **时间复杂度**:$O(2^n)$。其中 $n$ 为数组 $nums$ 的长度。 +- **空间复杂度**:$O(n)$。递归调用的栈空间深度不超过 $n$。 + +### 思路 2:深度优先搜索 + 记忆化搜索 + +在思路 1 中我们单独使用深度优先搜索对每位数字进行 `+` 或者 `-` 的方法超时了。所以我们考虑使用记忆化搜索的方式,避免进行重复搜索。 + +这里我们使用哈希表 `table` 记录遍历过的位置 `i` 及所得到的的当前和`cur_sum` 下的方案数,来避免重复搜索。具体步骤如下: + +1. 定义从位置 `0`、和为 `0` 开始,到达数组尾部位置为止,和为 `target` 的方案数为 `dfs(0, 0)`。 +2. 下面从位置 `0`、和为 `0` 开始,以深度优先搜索遍历每个位置。 +3. 如果当前位置 `i` 遍历完所有位置: + 1. 如果和 `cur_sum` 等于目标和 `target`,则返回方案数 `1`。 + 2. 如果和 `cur_sum` 不等于目标和 `target`,则返回方案数 `0`。 +4. 如果当前位置 `i`、和为 `cur_sum` 之前记录过(即使用 `table` 记录过对应方案数),则返回该方案数。 +5. 如果当前位置 `i`、和为 `cur_sum` 之前没有记录过,则: + 1. 递归搜索 `i + 1` 位置,和为 `cur_sum - nums[i]` 的方案数。 + 2. 递归搜索 `i + 1` 位置,和为 `cur_sum + nums[i]` 的方案数。 + 3. 将上述两个方案数加起来就是当前位置 `i`、和为 `cur_sum` 的方案数,将其记录到哈希表 `table` 中,并返回该方案数。 +6. 最终方案数为 `dfs(0, 0)`,将其作为答案返回即可。 + +### 思路 2:代码 + +```Python +class Solution: + def findTargetSumWays(self, nums: List[int], target: int) -> int: + size = len(nums) + table = dict() + + def dfs(i, cur_sum): + if i == size: + if cur_sum == target: + return 1 + else: + return 0 + + if (i, cur_sum) in table: + return table[(i, cur_sum)] + + cnt = dfs(i + 1, cur_sum - nums[i]) + dfs(i + 1, cur_sum + nums[i]) + table[(i, cur_sum)] = cnt + return cnt + + return dfs(0, 0) +``` + +### 思路 2:复杂度分析 + +- **时间复杂度**:$O(2^n)$。其中 $n$ 为数组 $nums$ 的长度。 +- **空间复杂度**:$O(n)$。递归调用的栈空间深度不超过 $n$。 + +### 思路 3:动态规划 假设数组中所有元素和为 `sum`,数组中所有符号为 `+` 的元素为 `sum_x`,符号为 `-` 的元素和为 `sum_y`。则 `target = sum_x - sum_y`。 @@ -19,11 +129,28 @@ 那么这道题就变成了,如何在数组中找到一个集合,使集合中元素和为 `(target + sum) / 2`。这就变为了求容量为 `(target + sum) / 2` 的 01 背包问题。 -动态规划的状态 `dp[i]` 表示为:填满容量为 `i` 的背包,有 `dp[i]` 种方法。 +###### 1. 定义状态 + +定义状态 `dp[i]` 表示为:填满容量为 `i` 的背包,有 `dp[i]` 种方法。 + +###### 2. 状态转移方程 + +填满容量为 `i` 的背包的方法数来源于: + +1. 不使用当前 `num`:只使用之前元素填满容量为 `i` 的背包的方法数。 +2. 使用当前 `num`:填满容量 `i - num` 的包的方法数,再填入 `num` 的方法数。 + +则动态规划的状态转移方程为:`dp[i] = dp[i] + dp[i - num]`。 -动态规划的状态转移方程为:`dp[i] = dp[i] + dp[i - num]`,意思为填满容量为 `i` 的背包的方法数 = 不使用当前 `num`,只使用之前元素填满容量为 `i` 的背包的方法数 + 填满容量 `i - num` 的包的方法数,再填入 `num` 的方法数。 +###### 3. 初始化 -## 代码 +初始状态下,默认填满容量为 `0` 的背包有 `1` 种办法。即 `dp[i] = 1`。 + +###### 4. 最终结果 + +根据状态定义,最后输出 `dp[sise]`(即填满容量为 `size` 的背包,有 `dp[size]` 种方法)即可,其中 `size` 为数组 `nums` 的长度。 + +### 思路 3:代码 ```Python class Solution: @@ -40,3 +167,8 @@ class Solution: return dp[size] ``` +### 思路 3:复杂度分析 + +- **时间复杂度**:$O(n)$。$n$ 为数组 $nums$ 的长度。 +- **空间复杂度**:$O(n)$。 + From fe352cf71e6b73f3525b9c9cdb88e753e1cf7b64 Mon Sep 17 00:00:00 2001 From: ITCharge Date: Mon, 5 Sep 2022 16:11:07 +0800 Subject: [PATCH 06/10] =?UTF-8?q?Update=200695.=20=E5=B2=9B=E5=B1=BF?= =?UTF-8?q?=E7=9A=84=E6=9C=80=E5=A4=A7=E9=9D=A2=E7=A7=AF.md?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...00345円244円247円351円235円242円347円247円257円.md" | 40 +++++++++++++++++-- 1 file changed, 36 insertions(+), 4 deletions(-) diff --git "a/Solutions/0695. 345円262円233円345円261円277円347円232円204円346円234円200円345円244円247円351円235円242円347円247円257円.md" "b/Solutions/0695. 345円262円233円345円261円277円347円232円204円346円234円200円345円244円247円351円235円242円347円247円257円.md" index 0bd0e692..28b35bab 100644 --- "a/Solutions/0695. 345円262円233円345円261円277円347円232円204円346円234円200円345円244円247円351円235円242円347円247円257円.md" +++ "b/Solutions/0695. 345円262円233円345円261円277円347円232円204円346円234円200円345円244円247円351円235円242円347円247円257円.md" @@ -5,15 +5,43 @@ ## 题目大意 -给定一个只包含 `0`、`1` 元素的二维数组,`1` 代表岛屿,`0` 代表水。一座岛的面积就是上下左右相邻的 `1` 所组成的连通块的数目。 +**描述**:给定一个只包含 `0`、`1` 元素的二维数组,`1` 代表岛屿,`0` 代表水。一座岛的面积就是上下左右相邻的 `1` 所组成的连通块的数目。 -要求:计算出最大的岛屿面积。 +**要求**:计算出最大的岛屿面积。 + +**说明**: + +- $m == grid.length$。 +- $n == grid[i].length$。 +- 1ドル \le m, n \le 50$。 +- $grid[i][j]$ 为 `0` 或 `1`。 + +**示例**: + +![](https://assets.leetcode.com/uploads/2021/05/01/maxarea1-grid.jpg) + +```Python +输入:grid = [[0,0,1,0,0,0,0,1,0,0,0,0,0],[0,0,0,0,0,0,0,1,1,1,0,0,0],[0,1,1,0,1,0,0,0,0,0,0,0,0],[0,1,0,0,1,1,0,0,1,0,1,0,0],[0,1,0,0,1,1,0,0,1,1,1,0,0],[0,0,0,0,0,0,0,0,0,0,1,0,0],[0,0,0,0,0,0,0,1,1,1,0,0,0],[0,0,0,0,0,0,0,1,1,0,0,0,0]] +输出:6 +解释:答案不应该是 11 ,因为岛屿只能包含水平或垂直这四个方向上的 1 。 + + +输入:grid = [[0,0,0,0,0,0,0,0]] +输出:0 +``` ## 解题思路 -使用深度优先搜索方法。遍历二维数组的每一个元素,对于每个值为 `1` 的元素,记下其面积。然后将该值置为 `0`(防止二次重复计算),再递归其上下左右四个位置,并将深度优先搜索搜到的值为 `1` 的元素个数,进行累积统计。 +### 思路 1:深度优先搜索 -## 代码 +1. 遍历二维数组的每一个元素,对于每个值为 `1` 的元素: + 1. 将该位置上的值置为 `0`(防止二次重复计算)。 + 2. 递归搜索该位置上下左右四个位置,并统计搜到值为 `1` 的元素个数。 + 3. 返回值为 `1` 的元素个数(即为该岛的面积)。 +2. 维护并更新最大的岛面积。 +3. 返回最大的到面积。 + +### 思路 1:代码 ```Python class Solution: @@ -39,3 +67,7 @@ class Solution: return ans ``` +### 思路 1:复杂度分析 + +- **时间复杂度**:$O(n \times m),ドル其中 $m$ 和 $n$ 分别为行数和列数。 +- **空间复杂度**:$O(n \times m)$。 From 5325cb796121926cd05b030b9ea1cca5bdcb0771 Mon Sep 17 00:00:00 2001 From: ITCharge Date: Mon, 5 Sep 2022 16:11:11 +0800 Subject: [PATCH 07/10] =?UTF-8?q?Update=200841.=20=E9=92=A5=E5=8C=99?= =?UTF-8?q?=E5=92=8C=E6=88=BF=E9=97=B4.md?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...31345円222円214円346円210円277円351円227円264円.md" | 51 ++++++++++++++++--- 1 file changed, 45 insertions(+), 6 deletions(-) diff --git "a/Solutions/0841. 351円222円245円345円214円231円345円222円214円346円210円277円351円227円264円.md" "b/Solutions/0841. 351円222円245円345円214円231円345円222円214円346円210円277円351円227円264円.md" index 6ce78e28..7b97e635 100644 --- "a/Solutions/0841. 351円222円245円345円214円231円345円222円214円346円210円277円351円227円264円.md" +++ "b/Solutions/0841. 351円222円245円345円214円231円345円222円214円346円210円277円351円227円264円.md" @@ -5,23 +5,58 @@ ## 题目大意 -有 `n` 个房间,编号为 `0` ~ `n - 1`,每个房间都有若干把钥匙,每把钥匙上都有一个编号,可以开启对应房间号的门。最初,除了 `0` 号房间外其他房间的门都是锁着的。 +**描述**:有 `n` 个房间,编号为 `0` ~ `n - 1`,每个房间都有若干把钥匙,每把钥匙上都有一个编号,可以开启对应房间号的门。最初,除了 `0` 号房间外其他房间的门都是锁着的。 -现在给定一个二维数组 `rooms`,`rooms[i][j]` 表示第 i 个房间的第 j 把钥匙所能开启的房间号。 +现在给定一个二维数组 `rooms`,`rooms[i][j]` 表示第 `i` 个房间的第 `j` 把钥匙所能开启的房间号。 -要求:判断是否能开启所有房间的门。如果能开启,则返回 `True`。否则返回 `False`。 +**要求**:判断是否能开启所有房间的门。如果能开启,则返回 `True`。否则返回 `False`。 + +**说明**: + +- $n == rooms.length$。 +- 2ドル \le n \le 1000$。 +- 0ドル \le rooms[i].length \le 1000$。 +- 1ドル \le sum(rooms[i].length) \le 3000$。 +- 0ドル \le rooms[i][j] < n$。 +- 所有 $rooms[i]$ 的值互不相同。 + +**示例**: + +```Python +输入:rooms = [[1],[2],[3],[]] +输出:True +解释: +我们从 0 号房间开始,拿到钥匙 1。 +之后我们去 1 号房间,拿到钥匙 2。 +然后我们去 2 号房间,拿到钥匙 3。 +最后我们去了 3 号房间。 +由于我们能够进入每个房间,我们返回 true。 + + +输入:rooms = [[1,3],[3,0,1],[2],[0]] +输出:False +解释:我们不能进入 2 号房间。 +``` ## 解题思路 +### 思路 1:深度优先搜索 + 当 `x` 号房间有 `y` 号房间的钥匙时,就可以认为我们可以通过 `x` 号房间去往 `y` 号房间。现在把 `n` 个房间看做是拥有 `n` 个节点的图,则上述关系可以看做是 `x` 与 `y` 点之间有一条有向边。 那么问题就变为了给定一张有向图,从 `0` 节点开始出发,问是否能到达所有的节点。 -我们可以先建图,然后可以从 `0` 节点开始,使用深度优先搜索的方式遍历整个图,并使用 `set` 集合来统计遍历到的节点个数。 +我们可以使用深度优先搜索的方式来解决这道题,具体做法如下: -最终判断一下遍历到的节点个数是否等于图的节点个数。如果等于,则返回 `True`,否则返回 `False`。 +1. 使用 set 集合变量 `visited` 来统计遍历到的节点个数。 +2. 从 `0` 节点开始,使用深度优先搜索的方式遍历整个图。 +3. 将当前节点 `x` 加入到集合 `visited` 中,遍历当前节点的邻接点。 + 1. 如果邻接点不再集合 `visited` 中,则继续递归遍历。 +4. 最后深度优先搜索完毕,判断一下遍历到的节点个数是否等于图的节点个数(即集合 `visited` 中的元素个数是否等于节点个数)。 + 1. 如果等于,则返回 `True` + 2. 如果不等于,则返回 `False`。 -## 代码 +### 思路 1:代码 ```Python class Solution: @@ -36,3 +71,7 @@ class Solution: return len(visited) == len(rooms) ``` +### 思路 1:复杂度分析 + +- **时间复杂度**:$O(n + m),ドル其中 $n$ 是房间的数量,$m$ 是所有房间中的钥匙数量的总数。 +- **空间复杂度**:$O(n),ドル递归调用的栈空间深度不超过 $n$。 \ No newline at end of file From ebbacf5ca3ef71e9e86ff9543b593f3858d5e1a1 Mon Sep 17 00:00:00 2001 From: ITCharge Date: Mon, 5 Sep 2022 16:11:27 +0800 Subject: [PATCH 08/10] Update 01.Bit-Operation.md --- .../06.Bit-Operation/01.Bit-Operation.md | 143 ++++++++++++++++++ 1 file changed, 143 insertions(+) diff --git a/Contents/09.Algorithm-Base/06.Bit-Operation/01.Bit-Operation.md b/Contents/09.Algorithm-Base/06.Bit-Operation/01.Bit-Operation.md index e69de29b..1806f18b 100644 --- a/Contents/09.Algorithm-Base/06.Bit-Operation/01.Bit-Operation.md +++ b/Contents/09.Algorithm-Base/06.Bit-Operation/01.Bit-Operation.md @@ -0,0 +1,143 @@ +## 1. 位运算简介 + +> **位运算(Bit Operation)**:在计算机内部,数是以「二进制(Binary)」的形式表示的。位运算就是直接对数的二进制进行计算操作,在程序中使用位运算进行操作,会大大提高程序的性能。 + +- **二进制数(Binary)**:用 `0` 和 `1` 两个数码来表示的数,它的基数是 `2`,进位规则是「逢二进一」,借位规则是「借一当二」。例如,十进制中的 `1`、`2`、`3`、`4` 对应的二进制数分别为 `001`、`010`、`011`、`100`。 + +二进制数中的每一位数字称为「位(Bit)」, `3` 位所能表示的最大二进制数是 `111`,也就是十进制中的 `7`,即 1ドル \times 2^2 + 1 \times 2^1 + 1 \times 2^0 = 7$。 + +在二进制的基础上,我们可以对二进制数进行相应的位运算。基本的位运算共 `6` 种,分别是:「按位与」、「按位或」、「按位异或」、「按位取反」、「左移」和「右移」。 + +## 2. 位运算基础操作 + +### 2.1 按位与运算 + +> **按位与运算(AND)**:按位与运算符 `&` 是双目运算符。其功能是对两个二进制数的每一个二进制位相与。只有对应的两个二进值位都为 `1` 时,结果位才为 `1`。当参与运算的是负数时,参与两个数均以补码出现。 + +- 按位与运算规则: + - `1 & 1 = 1` + - `1 & 0 = 0` + - `0 & 1 = 0` + - `0 & 0 = 0` + +例如,十进制中的 `3` 和 `5` 进行按位与运算,则结果如图所示: + +![](https://qcdn.itcharge.cn/images/20220601100205.png) + +按位与运算的通常用法: + +1. **清零**:任何数与 `0` 做按位与运算结果都为 `0`。 + - `(x & 0) == 0`。 +2. **取指定位**:比如要取一个数的低 `4` 位,则只需使用该数与二进制数 `00001111 (后 4 位为 1)`做按位与运算,结果就是这个数的低 `4` 位的值。 +3. **奇偶判断**:通过与 `1` 进行按位与运算,即可判断某个数是奇数还是偶数。 + - `(x & 1) == 0` 为偶数,`(x & 1) == 1` 为奇数。 + +### 2.2 按位或运算 + +> **按位或运算(OR)**:按位或运算符 `|` 是双目运算符。其功能对两个二进制数的每一个二进制位相或。只要对应的 `2` 个二进位有一个为 `1` 时,结果位就为 `1`。当参与运算的是负数时,参与两个数均以补码出现。 + +- 按位或运算规则: + - `1 | 1 = 1` + - `1 | 0 = 1` + - `0 | 1 = 1` + - `0 | 0 = 0` + +例如,十进制中的 `3` 和 `5` 进行按位或运算,则结果如图所示: + +![](https://qcdn.itcharge.cn/images/20220601101321.png) + +按位或运算的通常用法: + +1. **将某位设置为 `1`**:比如需要将一个数的低 `4` 位设置为 `1`,则只需使用该数与二进制数 `00001111 (后 4 位为 1)` 做按位或运算即可得到。 + +### 2.3 按位异或运算 + +> **按位异或运算(XOR)**:按位异或运算符 `^` 是双目运算符。其功能是对两个二进制数的每一个二进制位相异或。如果某位不相同则该位为 `1`,如果某位相同则该位为 `0`。当参与运算的是负数时,参与两个数均以补码出现。 + +- 按位异或运算规则: + - `0 ^ 0 = 0` + - `1 ^ 0 = 1` + - `0 ^ 1 = 1` + - `1 ^ 1 = 0` + +例如,十进制中的 `3` 和 `5` 进行按位异或运算,则结果如图所示: + +![](https://qcdn.itcharge.cn/images/20220601110009.png) + +按位异或运算的通常用法: + +1. **翻转指定位**:比如需要将一个数的低 `4` 位进行反转,则只需使用该数与二进制数 `00001111 (后 4 位为 1)` 做按位异或运算即可得到。 +2. **与 `0` 相异或值不变**:一个数与 `0` 做按位异或运算的结果不变。例如,`10101100 ^ 00000000 = 10101100`。 +3. **交换两个数**:通过按位异或运算可以实现交换两个数的目的。 + +```Python +a, b = 10, 20 +a ^= b +b ^= a +a ^= b +print(a, b) +``` + +### 2.4 按位取反运算 + +>**按位取反运算(NOT)**:按位取反运算符 `~` 是单目运算符。其功能是对一个二进制数的每一个二进制位取反。使数字 `1` 变为 `0`,`0` 变为 `1`。当参与运算的是负数时,参与的该数以补码出现。 + +- 按位取反运算规则: + - `~0 = 1` + - `~1 = 0` + +例如,十进制中的 `3` 进行按位取反运算,则结果如图所示: + +![](https://qcdn.itcharge.cn/images/20220601132807.png) + +### 2.5 按位左移运算 + +> **按位左移运算(SHL)**: 按位左移运算符 `<<` 是双目运算符。其功能是对一个二进制数的各个二进制位全部左移若干位(左边的二进制位丢弃,右边末尾补 `0`)。 + +例如,十进制中的 `3` 进行左移 `1` 位运算,则结果如图所示: + +![](https://qcdn.itcharge.cn/images/20220601171757.png) + +### 2.6 按位右移运算 + +> **按位右移运算(SHR)**: 按位右移运算符 `>>` 是双目运算符。其功能是对一个二进制数的各个二进制位全部右移若干位(右边的二进制位丢弃,正数左边开补 `0`,负数左边补 `1`)。 + +例如,十进制中的 `3` 进行右移 `1` 位运算,则结果如图所示: + +![](https://qcdn.itcharge.cn/images/20220601171822.png) + +## 2. 位运算的应用 + +### 2.1 位运算的常用应用 + +| 功 能 | 位运算 | 示例 | +| ----------------------------------------- | -------------------------------- | ---------------------- | +| **去掉最后一位** | x >> 1 | `101101 -> 10110` | +| **在最后加一个 `0`** | x << 1 | `101101 -> 1011010` | +| **在最后加一个 `1`** | (x << 1) + 1 | `101101 -> 1011011` | +| **把最后一位变成 `1`** | x | 1 | `101100 -> 101101` | +| **把最后一位变成 `0`** | x | 1 - 1 | `101101 -> 101100` | +| **最后一位取反** | x ^ 1 | `101101 -> 101100` | +| **把右数第 `k` 位变成 `1`** | x | (1 << (k - 1)) | `101001 -> 101101, k = 3` | +| **把右数第 `k` 位变成 `0`** | x & ~(1 << (k - 1)) | `101101 -> 101001, k = 3` | +| **右数第 `k` 位取反** | x ^ (1 << (k - 1)) | `101001 -> 101101, k = 3` | +| **取末尾 `3` 位** | x & 7 | `1101101 -> 101` | +| **取末尾 `k` 位** | x & 15 | `1101101 -> 1101, k = 4` | +| **取右数第 `k` 位** | x >> (k - 1) & 1 | `1101101 -> 1, k = 4` | +| **把末尾 `k` 位变成 `1`** | x | (1 << k - 1) | `101001 -> 101111, k = 4` | +| **末尾 `k` 位取反** | x ^ (1 << k - 1) | `101001 -> 100110, k = 4` | +| **把右边连续的 `1` 变成 `0`** | x & (x + 1) | `100101111 -> 100100000` | +| **把右边起第一个 `0` 变成 `1`** | x | (x + 1) | `100101111 -> 100111111` | +| **把右边连续的 `0` 变成 `1`** | x | (x - 1) | `11011000 -> 11011111` | +| **只保留右边连续的 `1`** | (x ^ (x + 1)) >> 1 | `100101111 -> 1111` | +| **去掉右边起第一个 `1` 的左边** | x & (x ^ (x - 1))x & (-x) | `100101000 -> 1000` | +| **从右边开始,把最后一个 `1` 改写成 `0`** | x & (x - 1) | `100101000 -> 100100000` | + +### 2.1 Brian Kernighan 算法 + + + +## 参考资料 + +- 【博文】[Python 中的按位运算符 |【生长吧!Python!】- 云社区 - 华为云](https://bbs.huaweicloud.com/blogs/280901) +- 【博文】[一文读懂位运算的使用 - 小黑说 Java - 掘金](https://juejin.cn/post/7011407264581943326) \ No newline at end of file From 374531fdb8813ae491df01837711904caa0d0671 Mon Sep 17 00:00:00 2001 From: ITCharge Date: Mon, 5 Sep 2022 16:11:32 +0800 Subject: [PATCH 09/10] Update 01.Graph-DFS.md --- .../02.Graph-Traversal/01.Graph-DFS.md | 176 ++++++++++++------ 1 file changed, 122 insertions(+), 54 deletions(-) diff --git a/Contents/08.Graph/02.Graph-Traversal/01.Graph-DFS.md b/Contents/08.Graph/02.Graph-Traversal/01.Graph-DFS.md index b93055b0..7e0720d7 100644 --- a/Contents/08.Graph/02.Graph-Traversal/01.Graph-DFS.md +++ b/Contents/08.Graph/02.Graph-Traversal/01.Graph-DFS.md @@ -2,17 +2,17 @@ ## 1. 深度优先搜索简介 -> **深度优先搜索算法**(Depth First Search):英文缩写为 DFS。是一种用于遍历或搜索树或图的算法。该算法沿着树的深度遍历树的节点,会尽可能深的搜索树的分支。当节点 `v` 的所在边都己被探寻过,搜索将回溯到发现节点 `v` 的那条边的起始节点。这一过程一直进行到已发现从源节点可达的所有节点为止。如果还存在未被发现的节点,则选择其中一个作为源节点并重复以上过程,整个进程反复进行直到所有节点都被访问为止。 +> **深度优先搜索算法**(Depth First Search):英文缩写为 DFS。是一种用于搜索树或图的算法。所谓深度优先,就是说每次都尝试向更深的节点走。 -深度优先搜索使用的是回溯思想,这种思想很适合使用「递归」来实现。而递归对问题的处理顺序,遵循了「后进先出」的规律。所以递归问题的处理,需要借助「堆栈」来实现。 +深度优先搜索采用了回溯思想,该算法沿着树的深度遍历树的节点,会尽可能深的搜索树的分支。当节点 `v` 的所在边都己被探寻过,搜索将回溯到发现节点 `v` 的那条边的起始节点。这一过程一直进行到已发现从源节点可达的所有节点为止。如果还存在未被发现的节点,则选择其中一个作为源节点并重复以上过程,整个进程反复进行直到所有节点都被访问为止。 -在深度优先遍历的过程中,我们需要将当前遍历节点 `v` 的相邻节点暂时存储起来,以便于在回退的时候可以继续访问它们。遍历到的节点顺序符合「后进先出」的特点,所以深度优先搜索可以通过「递归」或者「堆栈」来实现。 +在深度优先遍历的过程中,我们需要将当前遍历节点 `v` 的相邻节点暂时存储起来,以便于在回退的时候可以继续访问它们。遍历到的节点顺序符合「后进先出」的特点,这正是「递归」和「堆栈」所遵循的规律,所以深度优先搜索可以通过「递归」或者「堆栈」来实现。 ## 2. 深度优先搜索过程演示 接下来我们以一个无向图为例,演示一下深度优先搜索的过程。 -我们用邻接字典的方式存储无向图结构,对应结构代码如下: +我们用邻接字典的方式存储无向图结构,对应结构如下: ```Python # 定义无向图结构 @@ -26,11 +26,13 @@ graph = { } ``` -该无向图的结构如图左所示,图右为深度优先搜索的遍历路径。 +该无向图对应的邻接字典表示:无向图中有 `A`、`B`、`C`、`D`、`E`、`F` 共 `6` 个节点,其中与 `A` 节点相连的有 `B`、`C` 两个节点,与 `B` 节点相连的有 `A`、`C`、`D` 三个节点,等等。 + +该无向图的结构如图左所示,其深度优先搜索的遍历路径如图右所示。 ![](https://qcdn.itcharge.cn/images/20211214180351.png) -其对应的动态演示图如下所示。 +其深度优先搜索的遍历过程如下动态图所示。 ![](https://qcdn.itcharge.cn/images/20211214175901.gif) @@ -38,11 +40,11 @@ graph = { ### 3.1 基于递归实现的深度优先搜索实现步骤 -- `graph` 为存储无向图的字典变量,`visited` 为标记访问节点的 set 集合变量。`start` 为当前遍历边的开始节点。`def dfs_recursive(graph, start, visited):` 为递归实现的深度优先搜索方法。 -- 将 `start` 标记为已访问,即将 `start` 节点放入 `visited` 中(`visited.add(start)`)。 -- 访问节点 `start`,并对节点进行相关操作(看具体题目要求)。 -- 遍历与节点 `start` 相连并构成边的节点 `end`。 - - 如果 `end` 没有被访问过,则从 `end` 节点调用递归实现的深度优先搜索方法,即 `dfs_recursive(graph, end, visited)`。 +1. 定义 `graph` 为存储无向图的字典变量,`visited` 为标记访问节点的 set 集合变量。`start` 为当前遍历边的开始节点。`def dfs_recursive(graph, start, visited):` 为递归实现的深度优先搜索方法。 +2. 将 `start` 标记为已访问,即将 `start` 节点放入 `visited` 中(`visited.add(start)`)。 +3. 访问节点 `start`,并对节点进行相关操作(看具体题目要求)。 +4. 遍历与节点 `start` 相连并构成边的节点 `end`。 + 1. 如果 `end` 没有被访问过,则从 `end` 节点调用递归实现的深度优先搜索方法,即 `dfs_recursive(graph, end, visited)`。 ### 3.2 基于递归实现的深度优先搜索实现代码 @@ -112,31 +114,55 @@ def dfs_stack(graph, start): #### 5.1.2 题目大意 -给定一个由 `1`(陆地)和 `0`(水)组成的的二维网格 `grid`。 +**描述**:给定一个由字符 `'1'`(陆地)和字符 `'0'`(水)组成的的二维网格 `grid`。 -要求:计算网格中岛屿的数量。 +**要求**:计算网格中岛屿的数量。 -注意: +**说明**: -- 岛屿总是被水包围,并且每座岛屿只能由水平方向 / 竖直方向上相邻的陆地连接形成。 +- 岛屿总是被水包围,并且每座岛屿只能由水平方向和/或竖直方向上相邻的陆地连接形成。 - 此外,你可以假设该网格的四条边均被水包围。 +- $m == grid.length$。 +- $n == grid[i].length$。 +- 1ドル \le m, n \le 300$。 +- `grid[i][j]` 的值为 `'0'` 或 `'1'`。 + +**示例**: + +```Python +输入:grid = [ + ["1","1","1","1","0"], + ["1","1","0","1","0"], + ["1","1","0","0","0"], + ["0","0","0","0","0"] +] +输出:1 + + +输入:grid = [ + ["1","1","0","0","0"], + ["1","1","0","0","0"], + ["0","0","1","0","0"], + ["0","0","0","1","1"] +] +输出:3 +``` #### 5.1.3 解题思路 -如果把上下左右相邻的字符 `1` 看做是 `1` 个连通块,这道题的目的就是求解一共有多少个连通块。我们可以使用深度优先搜索来做。具体做法如下: +如果把上下左右相邻的字符 `'1'` 看做是 `1` 个连通块,这道题的目的就是求解一共有多少个连通块。 + +使用深度优先搜索或者广度优先搜索都可以。 -- 使用变量 `count` 统计连通块数目。然后遍历 `grid`。 -- 对于 `(i, j)` 位置上的元素: - - 如果 `grid[i][j] == 1`,调用深度优先搜索方法,令统计变量 + 1。 -- 深度优先搜索方法:初始位置 `(i, j)` 位置是一块岛屿,目的是找到该点的岛屿边界。 - - 将其置为 `0`(避免重复搜索)。然后从该点出发,递归遍历上、下、左、右四个方向,也就是递归遍历 `(i - 1, j)`、`(i, j - 1)`、`(i + 1, j)`、`(i, j + 1)` 四个方向。 - - 终止条件: - - `(i, j)` 超出矩阵范围。 - - `(i, j)` 位置上是水,即 `grid[i][j] == 0`。 +##### 思路 1:深度优先搜索 -- 最终统计出来的连通块数 `count` 就是我们要求的岛屿数量。 +1. 遍历 `grid` 。 +2. 对于每一个字符为 `'1'` 的元素,遍历其上下左右四个方向,并将该字符置为 `0`,保证下次不会被重复遍历。 +3. 如果超出边界,则返回 `0`。 +4. 对于 `(i, j)` 位置的元素来说,递归遍历的位置就是 `(i - 1, j)`、`(i, j - 1)`、`(i + 1, j)`、`(i, j + 1)` 四个方向。每次遍历到底,统计数记录一次。 +5. 最终统计出深度优先搜索的次数就是我们要求的岛屿数量。 -#### 5.1.4 代码 +##### 思路 1:代码 ```Python class Solution: @@ -146,10 +172,10 @@ class Solution: if i < 0 or i>= n or j < 0 or j>= m or grid[i][j] == '0': return 0 grid[i][j] = '0' - self.dfs(grid, i+1, j) - self.dfs(grid, i, j+1) - self.dfs(grid, i-1, j) - self.dfs(grid, i, j-1) + self.dfs(grid, i + 1, j) + self.dfs(grid, i, j + 1) + self.dfs(grid, i - 1, j) + self.dfs(grid, i, j - 1) def numIslands(self, grid: List[List[str]]) -> int: count = 0 @@ -161,6 +187,11 @@ class Solution: return count ``` +##### 思路 1:复杂度分析 + +- **时间复杂度**:$O(m \times n)$。其中 $m$ 和 $n$ 分别为行数和列数。 +- **空间复杂度**:$O(m \times n)$。 + ### 5.2 克隆图 #### 5.2.1 题目链接 @@ -169,45 +200,82 @@ class Solution: #### 5.2.2 题目大意 -给定一个无向连通图中一个节点的引用。 +**描述**:以每个节点的邻接列表形式(二维列表)给定一个无向连通图,其中 `adjList[i]` 表示值为 `i + 1`的节点的邻接列表,`adjList[i][j]` 表示值为 `i + 1` 的节点与值为 `adjList[i][j]` 的节点有一条边。 -要求:返回该图的深拷贝。 +**要求**:返回该图的深拷贝。 -#### 5.2.3 解题思路 +**说明**: -深拷贝的意思就是构建一张与原图结构、值均一样的图,但是所用的节点不再是原图节点的引用,即每个节点都要新建。 +- 节点数不超过 `100`。 +- 每个节点值 $Node.val$ 都是唯一的,1ドル \le Node.val \le 100$。 +- 无向图是一个简单图,这意味着图中没有重复的边,也没有自环。 +- 由于图是无向的,如果节点 `p` 是节点 `q` 的邻居,那么节点 `q` 也必须是节点 `p` 的邻居。 +- 图是连通图,你可以从给定节点访问到所有节点。 -可以使用深度优先搜索遍历图的所有节点,并在遍历图的同时新建节点,并构建新图。具体做法如下: +**示例**: -- 使用字典变量 `visited` 存储访问过的节点,键值对为 `原节点 : 新节点`。 -- 从 `node` 节点开始,调用深度优先搜索方法。 - - 如果 `node` 节点在 `visited` 中,则返回 `visited` 中存储的新节点,即 `visited[node]`。 - - 新建复制节点 `clone_node`,赋值为 `node.val`。 - - 将其加入到 `visited` 中,即 `visited[node] = clone_node`。 - - 遍历 `node` 节点的相邻节点,并从相邻节点开始,递归调用深度优先搜索方法。 - - 最后返回 `clone_node`。 +![](https://assets.leetcode-cn.com/aliyun-lc-upload/uploads/2020/02/01/133_clone_graph_question.png) -#### 5.2.4 代码 +```Python +输入:adjList = [[2,4],[1,3],[2,4],[1,3]] +输出:[[2,4],[1,3],[2,4],[1,3]] +解释: +图中有 4 个节点。 +节点 1 的值是 1,它有两个邻居:节点 2 和 4 。 +节点 2 的值是 2,它有两个邻居:节点 1 和 3 。 +节点 3 的值是 3,它有两个邻居:节点 2 和 4 。 +节点 4 的值是 4,它有两个邻居:节点 1 和 3 。 +``` + +![](https://assets.leetcode-cn.com/aliyun-lc-upload/uploads/2020/02/01/graph-1.png) ```Python -class Solution: - def dfs(self, node: 'Node', visited) -> 'Node': - if node in visited: - return visited[node] +输入:adjList = [[2],[1]] +输出:[[2],[1]] +``` - clone_node = Node(node.val, []) - visited[node] = clone_node - for neighbor in node.neighbors: - clone_node.neighbors.append(self.dfs(neighbor, visited)) - return clone_node +#### 5.2.3 解题思路 + +所谓深拷贝,就是构建一张与原图结构、值均一样的图,但是所用的节点不再是原图节点的引用,即每个节点都要新建。 + +可以用深度优先搜索或者广度优先搜索来做。 + +##### 思路 1:深度优先搜索 +1. 使用哈希表 `visitedDict` 来存储原图中被访问过的节点和克隆图中对应节点,键值对为 原图被访问过的节点:克隆图中对应节点。 +2. 从给定节点开始,以深度优先搜索的方式遍历原图。 + 1. 如果当前节点被访问过,则返回隆图中对应节点。 + 2. 如果当前节点没有被访问过,则创建一个新的节点,并保存在哈希表中。 + 3. 遍历当前节点的邻接节点列表,递归调用当前节点的邻接节点,并将其放入克隆图中对应节点。 +3. 递归结束,返回克隆节点。 + +##### 思路 1:代码 + +```Python +class Solution: def cloneGraph(self, node: 'Node') -> 'Node': if not node: return node - visited = dict() - return self.dfs(node, visited) + visitedDict = dict() + + def dfs(node: 'Node') -> 'Node': + if node in visitedDict: + return visitedDict[node] + + clone_node = Node(node.val, []) + visitedDict[node] = clone_node + for neighbor in node.neighbors: + clone_node.neighbors.append(dfs(neighbor)) + return clone_node + + return dfs(node) ``` +##### 思路 1:复杂度分析 + +- **时间复杂度**:$O(n)$。其中 $n$ 为图中节点数量。 +- **空间复杂度**:$O(n)$。 + ## 参考资料 - 【文章】[深度优先搜索 - LeetBook - 力扣(LeetCode)](https://leetcode.cn/leetbook/read/dfs/egx6xc/) From 55afc7225f61338b7ddeb379cfd2101a2c53ae1a Mon Sep 17 00:00:00 2001 From: ITCharge Date: Mon, 5 Sep 2022 16:11:37 +0800 Subject: [PATCH 10/10] Update Course-Git-01.md --- Assets/Course/Course-Git-01.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Assets/Course/Course-Git-01.md b/Assets/Course/Course-Git-01.md index 79f0960e..381763a6 100644 --- a/Assets/Course/Course-Git-01.md +++ b/Assets/Course/Course-Git-01.md @@ -1,4 +1,4 @@ -# Leetcode 刷题课程第 1 期:算法入门与数组篇 +# Leetcode 刷题课程第 1 期:算法入门与数组篇(14 天) ## 课程信息

AltStyle によって変換されたページ (->オリジナル) /