From deaf08a9ad225a113fd7c0efd40f161d93ca460c Mon Sep 17 00:00:00 2001 From: zj <294839611@qq.com> Date: Tue, 21 Mar 2023 16:15:58 +0800 Subject: [PATCH 001/122] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=20=E8=83=8C=E5=8C=85?= =?UTF-8?q?=E7=90=86=E8=AE=BA=E5=9F=BA=E7=A1=8001=E8=83=8C=E5=8C=85-1.md?= =?UTF-8?q?=20Java=E7=89=88=E6=9C=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- problems/背包理论基础01背包-1.md | 58 ++++++++++++++++++++++++++++++++ 1 file changed, 58 insertions(+) diff --git a/problems/背包理论基础01背包-1.md b/problems/背包理论基础01背包-1.md index ff0b6aba..1b04b057 100644 --- a/problems/背包理论基础01背包-1.md +++ b/problems/背包理论基础01背包-1.md @@ -338,6 +338,64 @@ public class BagProblem { ``` +```java +import java.util.Arrays; + +public class BagProblem { + public static void main(String[] args) { + int[] weight = {1,3,4}; + int[] value = {15,20,30}; + int bagSize = 4; + testWeightBagProblem(weight,value,bagSize); + } + + /** + * 初始化 dp 数组做了简化(给物品增加冗余维)。这样初始化dp数组,默认全为0即可。 + * dp[i][j] 表示从下标为[0 - i-1]的物品里任意取,放进容量为j的背包,价值总和最大是多少。 + * 其实是模仿背包重量从 0 开始,背包容量 j 为 0 的话,即dp[i][0],无论是选取哪些物品,背包价值总和一定为 0。 + * 可选物品也可以从无开始,也就是没有物品可选,即dp[0][j],这样无论背包容量为多少,背包价值总和一定为 0。 + * @param weight 物品的重量 + * @param value 物品的价值 + * @param bagSize 背包的容量 + */ + public static void testWeightBagProblem(int[] weight, int[] value, int bagSize){ + + // 创建dp数组 + int goods = weight.length; // 获取物品的数量 + int[][] dp = new int[goods + 1][bagSize + 1]; // 给物品增加冗余维,i = 0 表示没有物品可选 + + // 初始化dp数组,默认全为0即可 + // 填充dp数组 + for (int i = 1; i <= goods; i++) { + for (int j = 1; j <= bagSize; j++) { + if (j < weight[i - 1]) { // i - 1 对应物品 i + /** + * 当前背包的容量都没有当前物品i大的时候,是不放物品i的 + * 那么前i-1个物品能放下的最大价值就是当前情况的最大价值 + */ + dp[i][j] = dp[i - 1][j]; + } else { + /** + * 当前背包的容量可以放下物品i + * 那么此时分两种情况: + * 1、不放物品i + * 2、放物品i + * 比较这两种情况下,哪种背包中物品的最大价值最大 + */ + dp[i][j] = Math.max(dp[i - 1][j] , dp[i - 1][j - weight[i - 1]] + value[i - 1]); // i - 1 对应物品 i + } + } + } + + // 打印dp数组 + for(int[] arr : dp){ + System.out.println(Arrays.toString(arr)); + } + } +} + +``` + ### python ```python From 2d06a685ea39c988ad48b1a6025c8476cc06a640 Mon Sep 17 00:00:00 2001 From: NeedyChild <100189185+NeedyChild@users.noreply.github.com> Date: Tue, 9 May 2023 15:22:33 -0700 Subject: [PATCH 002/122] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=200494.=E7=9B=AE?= =?UTF-8?q?=E6=A0=87=E5=92=8C.md=20Java=E7=89=88=E6=9C=AC=E7=9A=84?= =?UTF-8?q?=E4=BA=8C=E7=BB=B4=E6=95=B0=E7=BB=84=E8=A7=A3=E6=B3=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- problems/0494.目标和.md | 79 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 79 insertions(+) diff --git a/problems/0494.目标和.md b/problems/0494.目标和.md index cc2bc8df..f8843d08 100644 --- a/problems/0494.目标和.md +++ b/problems/0494.目标和.md @@ -292,6 +292,85 @@ class Solution { } ``` +易于理解的二维数组版本: +```java +class Solution { + public int findTargetSumWays(int[] nums, int target) { + + // 01背包应用之“有多少种不同的填满背包最大容量的方法“ + // 易于理解的二维数组解法及详细注释 + + int sum = 0; + for(int i = 0; i < nums.length; i++) { + sum += nums[i]; + } + + // 注意nums[i] >= 0的题目条件,意味着sum也是所有nums[i]的绝对值之和 + // 这里保证了sum + target一定是大于等于零的,也就是left大于等于零(毕竟我们定义left大于right) + if(sum < Math.abs(target)){ + return 0; + } + + // 利用二元一次方程组将left用target和sum表示出来(替换掉right组合),详见代码随想录对此题的分析 + // 如果所求的left数组和为小数,则作为整数数组的nums里的任何元素自然是没有办法凑出这个小数的 + if((sum + target) % 2 != 0) { + return 0; + } + + int left = (sum + target) / 2; + + // dp[i][j]:遍历到数组第i个数时, left为j时的能装满背包的方法总数 + int[][] dp = new int[nums.length][left + 1]; + + // 初始化最上行(dp[0][j]),当nums[0] == j时(注意nums[0]和j都一定是大于等于零的,因此不需要判断等于-j时的情况),有唯一一种取法可取到j,dp[0][j]此时等于1 + // 其他情况dp[0][j] = 0 + // java整数数组默认初始值为0 + for(int j = 0; j <= left; j++) { + if(nums[0] == j) { + dp[0][j] = 1; + } + } + + // 初始化最左列(dp[i][0]) + // 当从nums数组的索引0到i的部分有n个0时(n > 0),每个0可以取+/-,因此有2的n次方中可以取到j = 0的方案 + // n = 0说明当前遍历到的数组部分没有0全为正数,因此只有一种方案可以取到j = 0(就是所有数都不取) + int numZeros = 0; + for(int i = 0; i < nums.length; i++) { + if(nums[i] == 0) { + numZeros++; + } + dp[i][0] = (int) Math.pow(2, numZeros); + + } + + // 递推公式分析: + // 当nums[i] > j时,这时候nums[i]一定不能取,所以是dp[i - 1][j]种方案数 + // nums[i] <= j时,num[i]可取可不取,因此方案数是dp[i - 1][j] + dp[i - 1][j - nums[i]] + // 由递推公式可知,先遍历i或j都可 + for(int i = 1; i < nums.length; i++) { + for(int j = 1; j <= left; j++) { + if(nums[i] > j) { + dp[i][j] = dp[i - 1][j]; + } else { + dp[i][j] = dp[i - 1][j] + dp[i - 1][j - nums[i]]; + } + } + } + + // 打印dp数组 + // for(int i = 0; i < nums.length; i++) { + // for(int j = 0; j <= left; j++) { + // System.out.print(dp[i][j] + " "); + // } + // System.out.println(""); + // } + + return dp[nums.length - 1][left]; + + } +} +``` + ### Python ```python class Solution: From 346e927f6c8a98594b444233dede3bca8f6ad5eb Mon Sep 17 00:00:00 2001 From: Terry Liu <102352821+Lozakaka@users.noreply.github.com> Date: Tue, 20 Jun 2023 17:51:21 -0400 Subject: [PATCH 003/122] =?UTF-8?q?=E6=96=B0=E5=A2=9Ejava=E8=A7=A3?= =?UTF-8?q?=E6=B3=95=20for=20leetcode=205.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 新增java解法 for leetcode 5. 感覺卡哥可以提一下,其實在下一偏有提到,但是真的有關聯的這一篇沒有提到:這一題稍微改一下就能通過兩題,這一點我沒有寫在這個fork上。 --- problems/0647.回文子串.md | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/problems/0647.回文子串.md b/problems/0647.回文子串.md index e172de54..084b9f74 100644 --- a/problems/0647.回文子串.md +++ b/problems/0647.回文子串.md @@ -304,7 +304,38 @@ class Solution { } } ``` +LeetCode 5. Longest Palindromic Substring(LeetCode 647. 同一題的思路改一下、加一點,就能通過LeetCode 5) +```java +class Solution { + public String longestPalindrome(String s) { + //題目要求要return 最長的回文連續子串,故需要記錄當前最長的連續回文子串長度、最終起點、最終終點。 + int finalStart = 0; + int finalEnd = 0; + int finalLen = 0; + char[] chars = s.toCharArray(); + int len = chars.length; + + boolean[][] dp = new boolean[len][len]; + for (int i = len - 1; i >= 0; i--) { + for (int j = i; j < len; j++) { + if (chars[i] == chars[j] && (j - i <= 1 || dp[i + 1][j - 1])) + dp[i][j] = true; + //和LeetCode 647,差別就在這個if statement。 + //如果當前[i, j]範圍內的substring是回文子串(dp[i][j]) 且(&&) 長度大於當前要記錄的最終長度(j - i + 1 > finalLen) + //我們就更新 當前最長的連續回文子串長度、最終起點、最終終點 + if (dp[i][j] && j - i + 1 > finalLen) { + finalLen = j - i + 1; + finalStart = i; + finalEnd = j; + } + } + } + //String.substring這個method的用法是[起點, 終點),包含起點,不包含終點(左閉右開區間),故終點 + 1。 + return s.substring(finalStart, finalEnd + 1); + } +} +``` Python: From 1f31f092f1ec713a6df0f7617c39bc2107a9ba5f Mon Sep 17 00:00:00 2001 From: Ao Liu <63785048+Ao-Last@users.noreply.github.com> Date: Wed, 21 Jun 2023 17:38:00 +0800 Subject: [PATCH 004/122] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=200242.=E6=9C=89?= =?UTF-8?q?=E6=95=88=E7=9A=84=E5=AD=97=E6=AF=8D=E5=BC=82=E4=BD=8D=E8=AF=8D?= =?UTF-8?q?.md=20md=E6=A0=BC=E5=BC=8F=E9=94=99=E8=AF=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- problems/0242.有效的字母异位词.md | 1 + 1 file changed, 1 insertion(+) diff --git a/problems/0242.有效的字母异位词.md b/problems/0242.有效的字母异位词.md index 101dd6f2..4ea43947 100644 --- a/problems/0242.有效的字母异位词.md +++ b/problems/0242.有效的字母异位词.md @@ -163,6 +163,7 @@ class Solution(object): a_count = Counter(s) b_count = Counter(t) return a_count == b_count +``` Go: From b92fcc936e4515fd922e4f00ecfd0e0816f275b4 Mon Sep 17 00:00:00 2001 From: Terry Liu <102352821+Lozakaka@users.noreply.github.com> Date: Thu, 22 Jun 2023 03:13:04 -0400 Subject: [PATCH 005/122] =?UTF-8?q?=E8=A7=A3=E6=B1=BA=E8=B7=91=E6=9D=BF?= =?UTF-8?q?=E5=95=8F=E9=A1=8C=20+=20=E6=8F=90=E4=BE=9Bjava=E8=A7=A3?= =?UTF-8?q?=E6=B3=95(=E5=92=8C=E5=8D=A1=E5=93=A5=E9=82=8F=E8=BC=AF?= =?UTF-8?q?=E4=B8=80=E8=87=B4)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 跑版: 原本的code box 結束的```不見了,所以看不到結尾圖片。 新解法和原本JAVA解法的差異: 原版的應該是自己寫的DFS,邏輯大致一致,但還是有差異,故提供用卡哥C++ code改的版本 --- problems/0200.岛屿数量.深搜版.md | 42 ++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/problems/0200.岛屿数量.深搜版.md b/problems/0200.岛屿数量.深搜版.md index 6d42162a..c30ace19 100644 --- a/problems/0200.岛屿数量.深搜版.md +++ b/problems/0200.岛屿数量.深搜版.md @@ -176,6 +176,48 @@ public void dfs(char[][] grid, int i, int j){ dfs(grid,i,j + 1); dfs(grid,i,j - 1); } +``` +```java +//graph - dfs (和卡哥的代碼邏輯一致) +class Solution { + boolean[][] visited; + int dir[][] = { + {0, 1}, //right + {1, 0}, //down + {-1, 0}, //up + {0, -1} //left + }; + public int numIslands(char[][] grid) { + int count = 0; + visited = new boolean[grid.length][grid[0].length]; + + for(int i = 0; i < grid.length; i++){ + for(int j = 0; j < grid[0].length; j++){ + if(visited[i][j] == false && grid[i][j] == '1'){ + count++; + dfs(grid, i, j); + } + } + } + return count; + } + + private void dfs(char[][]grid, int x, int y){ + if(visited[x][y] == true || grid[x][y] == '0') + return; + + visited[x][y] = true; + + for(int i = 0; i < 4; i++){ + int nextX = x + dir[i][0]; + int nextY = y + dir[i][1]; + if(nextX < 0 || nextY < 0 || nextX >= grid.length || nextY >= grid[0].length) + continue; + dfs(grid, nextX, nextY); + } + } +} +```

From 33eca1635693f64d0eeb6d7c477093665dded20b Mon Sep 17 00:00:00 2001 From: Terry Liu <102352821+Lozakaka@users.noreply.github.com> Date: Sat, 24 Jun 2023 20:18:36 -0400 Subject: [PATCH 006/122] =?UTF-8?q?=E6=96=B0=E5=A2=9Ejava=E8=A7=A3?= =?UTF-8?q?=E6=B3=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1. 調整語言順序 2. 新增java - DFS, java - BFS解法 --- problems/0695.岛屿的最大面积.md | 162 +++++++++++++++++++++++++------- 1 file changed, 129 insertions(+), 33 deletions(-) diff --git a/problems/0695.岛屿的最大面积.md b/problems/0695.岛屿的最大面积.md index e5deb897..37a601bc 100644 --- a/problems/0695.岛屿的最大面积.md +++ b/problems/0695.岛屿的最大面积.md @@ -189,6 +189,135 @@ public: ``` # 其它语言版本 +## Java +### DFS +```java +// DFS +class Solution { + int[][] dir = { + {0, 1}, //right + {1, 0}, //down + {0, -1}, //left + {-1, 0} //up + }; + boolean visited[][]; + int count; + public int maxAreaOfIsland(int[][] grid) { + int res = 0; + visited = new boolean[grid.length][grid[0].length]; + for(int i = 0; i < grid.length; i++){ + for(int j = 0; j < grid[0].length; j++){ + if(visited[i][j] == false && grid[i][j] == 1){ + count = 0; + dfs(grid, i, j); + res = Math.max(res, count); + } + } + } + return res; + } + private void dfs(int[][] grid, int x, int y){ + if(visited[x][y] == true || grid[x][y] == 0) + return; + + visited[x][y] = true; + count++; + + for(int i = 0; i < 4; i++){ + int nextX = x + dir[i][0]; + int nextY = y + dir[i][1]; + + if(nextX < 0 || nextY < 0 || nextX >= grid.length || nextY >= grid[0].length) + continue; + dfs(grid, nextX, nextY); + } + } +} + + +``` +### BFS +```java +//BFS +class Solution { + int[][] dir = { + {0, 1}, {1, 0}, {0, -1}, {-1, 0} + }; + + int count; + boolean visited[][]; + + public int maxAreaOfIsland(int[][] grid) { + int res = 0; + visited = new boolean[grid.length][grid[0].length]; + + for(int i = 0; i < grid.length; i++){ + for(int j = 0; j < grid[0].length; j++){ + if(visited[i][j] == false && grid[i][j] == 1){ + count = 0; + bfs(grid, i, j); + res = Math.max(res, count); + } + } + } + return res; + } + private void bfs(int[][] grid, int x, int y){ + Queue que = new LinkedList<>(); + que.offer(x); + que.offer(y); + visited[x][y] = true; + count++; + + while(!que.isEmpty()){ + int currX = que.poll(); + int currY = que.poll(); + + for(int i = 0; i < 4; i++){ + int nextX = currX + dir[i][0]; + int nextY = currY + dir[i][1]; + + if(nextX < 0 || nextY < 0 || nextX >= grid.length || nextY >= grid[0].length) + continue; + if(visited[nextX][nextY] == false && grid[nextX][nextY] == 1){ + que.offer(nextX); + que.offer(nextY); + visited[nextX][nextY] = true; + count++; + } + } + } + } +} +``` +### DFS 優化(遇到島嶼後,就把他淹沒) +```java +//这里使用深度优先搜索 DFS 来完成本道题目。我们使用 DFS 计算一个岛屿的面积,同时维护计算过的最大的岛屿面积。同时,为了避免对岛屿重复计算,我们在 DFS 的时候对岛屿进行 “淹没” 操作,即将岛屿所占的地方置为 0。 +public int maxAreaOfIsland(int[][] grid) { + int res = 0; + for(int i = 0;i < grid.length;i++){ + for(int j = 0;j < grid[0].length;j++){ + //每遇到一个岛屿就计算这个岛屿的面积同时”淹没“这个岛屿 + if(grid[i][j] == 1){ + //每次计算一个岛屿的面积都要与res比较,维护最大的岛屿面积作为最后的答案 + res = Math.max(res,dfs(grid,i,j)); + } + } + } + return res; +} +public int dfs(int[][] grid,int i,int j){ + //搜索边界:i,j超过grid的范围或者当前元素为0,即当前所在的地方已经是海洋 + if(i < 0 || i >= grid.length || j < 0 || j >= grid[0].length || grid[i][j] == 0) return 0; + //淹没土地,防止后续被重复计算 + grid[i][j] = 0; + //递归的思路:要求当前土地(i,j)所在的岛屿的面积,则等于1加上下左右相邻的土地的总面积 + return 1 + dfs(grid,i - 1,j) + + dfs(grid,i + 1,j) + + dfs(grid,i,j + 1) + + dfs(grid,i,j - 1); +} +``` ## Python ### BFS @@ -261,39 +390,6 @@ class Solution: if 0 <= new_x < len(grid) and 0 <= new_y < len(grid[0]): self.dfs(grid, visited, new_x, new_y) ``` - - - -## Java - -这里使用深度优先搜索 DFS 来完成本道题目。我们使用 DFS 计算一个岛屿的面积,同时维护计算过的最大的岛屿面积。同时,为了避免对岛屿重复计算,我们在 DFS 的时候对岛屿进行 “淹没” 操作,即将岛屿所占的地方置为 0。 - -```java -public int maxAreaOfIsland(int[][] grid) { - int res = 0; - for(int i = 0;i < grid.length;i++){ - for(int j = 0;j < grid[0].length;j++){ - //每遇到一个岛屿就计算这个岛屿的面积同时”淹没“这个岛屿 - if(grid[i][j] == 1){ - //每次计算一个岛屿的面积都要与res比较,维护最大的岛屿面积作为最后的答案 - res = Math.max(res,dfs(grid,i,j)); - } - } - } - return res; -} -public int dfs(int[][] grid,int i,int j){ - //搜索边界:i,j超过grid的范围或者当前元素为0,即当前所在的地方已经是海洋 - if(i < 0 || i >= grid.length || j < 0 || j >= grid[0].length || grid[i][j] == 0) return 0; - //淹没土地,防止后续被重复计算 - grid[i][j] = 0; - //递归的思路:要求当前土地(i,j)所在的岛屿的面积,则等于1加上下左右相邻的土地的总面积 - return 1 + dfs(grid,i - 1,j) + - dfs(grid,i + 1,j) + - dfs(grid,i,j + 1) + - dfs(grid,i,j - 1); -} -```

From 2b3ce4453520a16bac6d65c2b3295cc65b90f00e Mon Sep 17 00:00:00 2001 From: Terry Liu <102352821+Lozakaka@users.noreply.github.com> Date: Sat, 24 Jun 2023 23:38:40 -0400 Subject: [PATCH 007/122] =?UTF-8?q?=E6=96=B0=E5=A2=9Ejava=E8=A7=A3?= =?UTF-8?q?=E6=B3=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- problems/1020.飞地的数量.md | 126 +++++++++++++++++++++++++++++++++++- 1 file changed, 124 insertions(+), 2 deletions(-) diff --git a/problems/1020.飞地的数量.md b/problems/1020.飞地的数量.md index e92b2412..7538d774 100644 --- a/problems/1020.飞地的数量.md +++ b/problems/1020.飞地的数量.md @@ -149,7 +149,63 @@ public: ### Java -深度优先遍历版本: +深度优先遍历(没有终止条件 + 空間優化(淹沒島嶼,沒有使用visited數組)) +```java +//DFS +class Solution { + int count = 0; + int[][] dir ={ + {0, 1}, + {1, 0}, + {-1, 0}, + {0, -1} + }; + private void dfs(int[][] grid, int x, int y){ + if(grid[x][y] == 0) + return; + + grid[x][y] = 0; + count++; + + for(int i = 0; i < 4; i++){ + int nextX = x + dir[i][0]; + int nextY = y + dir[i][1]; + + if(nextX < 0 || nextY < 0 || nextX >= grid.length || nextY >= grid[0].length) + continue; + dfs(grid, nextX, nextY); + } + + } + + public int numEnclaves(int[][] grid) { + for(int i = 0; i < grid.length; i++){ + if(grid[i][0] == 1) + dfs(grid, i, 0); + if(grid[i][grid[0].length - 1] == 1) + dfs(grid, i, grid[0].length - 1); + } + //初始化的時候,j 的上下限有調整過,必免重複操作。 + for(int j = 1; j < grid[0].length - 1; j++){ + if(grid[0][j] == 1) + dfs(grid, 0, j); + if(grid[grid.length - 1][j] == 1) + dfs(grid, grid.length - 1, j); + } + count = 0; + + for(int i = 1; i < grid.length - 1; i++){ + for(int j = 1; j < grid[0].length - 1; j++){ + if(grid[i][j] == 1) + dfs(grid, i, j); + } + } + return count; + } +} +``` + +深度优先遍历(没有终止条件) ```java class Solution { @@ -206,7 +262,7 @@ class Solution { } ``` -广度优先遍历版本: +广度优先遍历(使用visited數組) ```java class Solution { @@ -269,6 +325,72 @@ class Solution { } ``` +廣度优先遍历(空間優化(淹沒島嶼,沒有使用visited數組)) +```java +//BFS +class Solution { + int count = 0; + int[][] dir ={ + {0, 1}, + {1, 0}, + {-1, 0}, + {0, -1} + }; + private void bfs(int[][] grid, int x, int y){ + Queue que = new LinkedList<>(); + que.offer(x); + que.offer(y); + count++; + grid[x][y] = 0; + + while(!que.isEmpty()){ + int currX = que.poll(); + int currY = que.poll(); + + for(int i = 0; i < 4; i++){ + int nextX = currX + dir[i][0]; + int nextY = currY + dir[i][1]; + + if(nextX < 0 || nextY < 0 || nextX >= grid.length || nextY >= grid[0].length) + continue; + + if(grid[nextX][nextY] == 1){ + que.offer(nextX); + que.offer(nextY); + count++; + grid[nextX][nextY] = 0; + } + } + } + } + + public int numEnclaves(int[][] grid) { + for(int i = 0; i < grid.length; i++){ + if(grid[i][0] == 1) + bfs(grid, i, 0); + if(grid[i][grid[0].length - 1] == 1) + bfs(grid, i, grid[0].length - 1); + } + for(int j = 1; j < grid[0].length; j++){ + if(grid[0][j] == 1) + bfs(grid, 0 , j); + if(grid[grid.length - 1][j] == 1) + bfs(grid, grid.length - 1, j); + } + count = 0; + for(int i = 1; i < grid.length - 1; i++){ + for(int j = 1; j < grid[0].length - 1; j++){ + if(grid[i][j] == 1) + bfs(grid,i ,j); + } + } + return count; + } +} + + +``` + ### Python 深度优先遍历 From cdc5a1e9e47690fee5c5f5b34d66f643d6e08907 Mon Sep 17 00:00:00 2001 From: Terry Liu <102352821+Lozakaka@users.noreply.github.com> Date: Mon, 26 Jun 2023 21:37:58 -0400 Subject: [PATCH 008/122] =?UTF-8?q?=E6=96=B0=E5=A2=9EJAVA=E8=A7=A3?= =?UTF-8?q?=E6=B3=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1. java的BFS解法有寫一個helper function去呼叫 2. java's DFS with 終止條件 --- problems/0130.被围绕的区域.md | 89 +++++++++++++++++++++++++++++++++++ 1 file changed, 89 insertions(+) diff --git a/problems/0130.被围绕的区域.md b/problems/0130.被围绕的区域.md index abb68e19..e244873b 100644 --- a/problems/0130.被围绕的区域.md +++ b/problems/0130.被围绕的区域.md @@ -188,6 +188,54 @@ class Solution { } } ``` +```Java +//BFS(使用helper function) +class Solution { + int[][] dir ={{0, 1}, {1, 0}, {0, -1}, {-1, 0}}; + public void solve(char[][] board) { + for(int i = 0; i < board.length; i++){ + if(board[i][0] == 'O') bfs(board, i, 0); + if(board[i][board[0].length - 1] == 'O') bfs(board, i, board[0].length - 1); + } + + for(int j = 1 ; j < board[0].length - 1; j++){ + if(board[0][j] == 'O') bfs(board, 0, j); + if(board[board.length - 1][j] == 'O') bfs(board, board.length - 1, j); + } + + for(int i = 0; i < board.length; i++){ + for(int j = 0; j < board[0].length; j++){ + if(board[i][j] == 'O') board[i][j] = 'X'; + if(board[i][j] == 'A') board[i][j] = 'O'; + } + } + } + private void bfs(char[][] board, int x, int y){ + Queue que = new LinkedList<>(); + board[x][y] = 'A'; + que.offer(x); + que.offer(y); + + while(!que.isEmpty()){ + int currX = que.poll(); + int currY = que.poll(); + + for(int i = 0; i < 4; i++){ + int nextX = currX + dir[i][0]; + int nextY = currY + dir[i][1]; + + if(nextX < 0 || nextY < 0 || nextX >= board.length || nextY >= board[0].length) + continue; + if(board[nextX][nextY] == 'X'|| board[nextX][nextY] == 'A') + continue; + bfs(board, nextX, nextY); + } + } + } +} + +``` + ```Java // 深度优先遍历 // 使用 visited 数组进行标记 @@ -296,6 +344,47 @@ class Solution { } } ``` +```java +//DFS(有終止條件) +class Solution { + int[][] dir ={{0, 1}, {1, 0}, {0, -1}, {-1, 0}}; + public void solve(char[][] board) { + + for(int i = 0; i < board.length; i++){ + if(board[i][0] == 'O') dfs(board, i, 0); + if(board[i][board[0].length - 1] == 'O') dfs(board, i, board[0].length - 1); + } + + for(int j = 1 ; j < board[0].length - 1; j++){ + if(board[0][j] == 'O') dfs(board, 0, j); + if(board[board.length - 1][j] == 'O') dfs(board, board.length - 1, j); + } + + for(int i = 0; i < board.length; i++){ + for(int j = 0; j < board[0].length; j++){ + if(board[i][j] == 'O') board[i][j] = 'X'; + if(board[i][j] == 'A') board[i][j] = 'O'; + } + } + } + + private void dfs(char[][] board, int x, int y){ + if(board[x][y] == 'X'|| board[x][y] == 'A') + return; + board[x][y] = 'A'; + for(int i = 0; i < 4; i++){ + int nextX = x + dir[i][0]; + int nextY = y + dir[i][1]; + + if(nextX < 0 || nextY < 0 || nextX >= board.length || nextY >= board[0].length) + continue; + // if(board[nextX][nextY] == 'X'|| board[nextX][nextY] == 'A') + // continue; + dfs(board, nextX, nextY); + } + } +} +```

From f8f8539393813c4f4ec73427d5eb157acc641fe1 Mon Sep 17 00:00:00 2001 From: Yifan Liu <39271063+yifanliuu@users.noreply.github.com> Date: Thu, 29 Jun 2023 13:49:22 +0800 Subject: [PATCH 009/122] =?UTF-8?q?=E6=96=B0=E5=A2=9Epython=E8=A7=A3?= =?UTF-8?q?=E6=B3=95=E9=80=92=E5=BD=92=E7=89=88=200024.=E4=B8=A4=E4=B8=A4?= =?UTF-8?q?=E4=BA=A4=E6=8D=A2=E9=93=BE=E8=A1=A8=E4=B8=AD=E7=9A=84=E8=8A=82?= =?UTF-8?q?=E7=82=B9.md?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- problems/0024.两两交换链表中的节点.md | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/problems/0024.两两交换链表中的节点.md b/problems/0024.两两交换链表中的节点.md index ab204d89..d7c03b64 100644 --- a/problems/0024.两两交换链表中的节点.md +++ b/problems/0024.两两交换链表中的节点.md @@ -177,6 +177,30 @@ class Solution { ``` Python: +```python +# 递归版本 +# Definition for singly-linked list. +# class ListNode: +# def __init__(self, val=0, next=None): +# self.val = val +# self.next = next + +class Solution: + def swapPairs(self, head: Optional[ListNode]) -> Optional[ListNode]: + if head is None or head.next is None: + return head + + # 待翻转的两个node分别是pre和cur + pre = head + cur = head.next + next = head.next.next + + cur.next = pre # 交换 + pre.next = self.swapPairs(next) # 将以next为head的后续链表两两交换 + + return cur +``` + ```python # Definition for singly-linked list. # class ListNode: From 5085e78e601fa6450e80b0d5d9b060df26857dcb Mon Sep 17 00:00:00 2001 From: Leon He Date: Thu, 29 Jun 2023 11:25:27 -0700 Subject: [PATCH 010/122] =?UTF-8?q?Update=200200.=E5=B2=9B=E5=B1=BF?= =?UTF-8?q?=E6=95=B0=E9=87=8F.=E5=B9=BF=E6=90=9C=E7=89=88.md?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add python solution --- problems/0200.岛屿数量.广搜版.md | 41 ++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/problems/0200.岛屿数量.广搜版.md b/problems/0200.岛屿数量.广搜版.md index 39af9f50..2bb0973a 100644 --- a/problems/0200.岛屿数量.广搜版.md +++ b/problems/0200.岛屿数量.广搜版.md @@ -200,3 +200,44 @@ class Solution { +``` +### Python +BFS solution +```python +class Solution: + def __init__(self): + self.dirs = [[0, 1], [1, 0], [-1, 0], [0, -1]] + + def numIslands(self, grid: List[List[str]]) -> int: + m = len(grid) + n = len(grid[0]) + visited = [[False]*n for _ in range(m)] + res = 0 + for i in range(m): + for j in range(n): + if visited[i][j] == False and grid[i][j] == '1': + res += 1 + self.bfs(grid, i, j, visited) # Call bfs within this condition + return res + + def bfs(self, grid, i, j, visited): + q = deque() + q.append((i,j)) + visited[i][j] = True + while q: + x, y = q.popleft() + for k in range(4): + next_i = x + self.dirs[k][0] + next_j = y + self.dirs[k][1] + + if next_i < 0 or next_i >= len(grid): + continue + if next_j < 0 or next_j >= len(grid[0]): + continue + if visited[next_i][next_j]: + continue + if grid[next_i][next_j] == '0': + continue + q.append((next_i, next_j)) + visited[next_i][next_j] = True +``` From 6cd9b165290298868b6b86ca88693c5b77408841 Mon Sep 17 00:00:00 2001 From: Terry Liu <102352821+Lozakaka@users.noreply.github.com> Date: Thu, 29 Jun 2023 16:56:19 -0400 Subject: [PATCH 011/122] =?UTF-8?q?=E6=96=B0=E5=A2=9Ejava=20DFS=E8=A7=A3?= =?UTF-8?q?=E6=B3=95=E7=95=B6=E4=BD=9C=E5=BB=B6=E4=BC=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- problems/0463.岛屿的周长.md | 47 +++++++++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/problems/0463.岛屿的周长.md b/problems/0463.岛屿的周长.md index 2f399f40..18f1d01e 100644 --- a/problems/0463.岛屿的周长.md +++ b/problems/0463.岛屿的周长.md @@ -142,6 +142,53 @@ class Solution { return landSum * 4 - cover * 2; } } +// 延伸 - 傳統DFS解法(使用visited數組)(遇到邊界 或是 海水 就edge ++) +class Solution { + int dir[][] ={ + {0, 1}, + {0, -1}, + {1, 0}, + {-1, 0} + }; + + boolean visited[][]; + int res = 0; + + public int islandPerimeter(int[][] grid) { + int row = grid.length; + int col = grid[0].length; + visited = new boolean[row][col]; + + int result = 0; + + for(int i = 0; i < row; i++){ + for(int j = 0; j < col; j++){ + if(visited[i][j] == false && grid[i][j] == 1) + result += dfs(grid, i, j); + } + } + return result; + } + + private int dfs(int[][] grid, int x, int y){ + //如果遇到 邊界(x < 0 || y < 0 || x >= grid.length || y >= grid[0].length)或是 遇到海水(grid[x][y] == 0)就return 1(edge + 1) + if(x < 0 || y < 0 || x >= grid.length || y >= grid[0].length || grid[x][y] == 0) + return 1; + //如果該地已經拜訪過,就return 0 避免重複計算 + if(visited[x][y]) + return 0; + int temp = 0; + visited[x][y] = true; + for(int i = 0; i < 4; i++){ + int nextX = x + dir[i][0]; + int nextY = y + dir[i][1]; + //用temp 把edge存起來 + temp +=dfs(grid, nextX, nextY); + } + return temp; + } +} + ``` Python: From c1b2141ea20e58b031c874f55c341fbfc8b69470 Mon Sep 17 00:00:00 2001 From: fwqaaq Date: Fri, 30 Jun 2023 10:22:49 +0800 Subject: [PATCH 012/122] =?UTF-8?q?Update=200123.=E4=B9=B0=E5=8D=96?= =?UTF-8?q?=E8=82=A1=E7=A5=A8=E7=9A=84=E6=9C=80=E4=BD=B3=E6=97=B6=E6=9C=BA?= =?UTF-8?q?III.md=20about=20rust?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- problems/0123.买卖股票的最佳时机III.md | 27 ++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/problems/0123.买卖股票的最佳时机III.md b/problems/0123.买卖股票的最佳时机III.md index 6ac9a576..f5b95946 100644 --- a/problems/0123.买卖股票的最佳时机III.md +++ b/problems/0123.买卖股票的最佳时机III.md @@ -413,7 +413,34 @@ function maxProfit(prices: number[]): number { }; ``` +Rust: +> 版本一 + +```rust +impl Solution { + pub fn max_profit(prices: Vec) -> i32 { + /* + * 定义 5 种状态: + * 0: 没有操作, 1: 第一次买入, 2: 第一次卖出, 3: 第二次买入, 4: 第二次卖出 + */ + let mut dp = vec![vec![0; 5]; prices.len()]; + dp[0][1] = -prices[0]; + dp[0][3] = -prices[0]; + + for (i, &p) in prices.iter().enumerate().skip(1) { + // 不操作 + // dp[i][0] = dp[i - 1][0]; + dp[i][1] = dp[i - 1][1].max(-p); + dp[i][2] = dp[i - 1][2].max(dp[i - 1][1] + p); + dp[i][3] = dp[i - 1][3].max(dp[i - 1][2] - p); + dp[i][4] = dp[i - 1][4].max(dp[i - 1][3] + p); + } + + dp[prices.len() - 1][4] + } +} +```

From 85daaae4656f0411eab2e1ec6ff1bbfa608120c1 Mon Sep 17 00:00:00 2001 From: fwqaaq Date: Fri, 30 Jun 2023 10:31:32 +0800 Subject: [PATCH 013/122] =?UTF-8?q?Update=200123.=E4=B9=B0=E5=8D=96?= =?UTF-8?q?=E8=82=A1=E7=A5=A8=E7=9A=84=E6=9C=80=E4=BD=B3=E6=97=B6=E6=9C=BA?= =?UTF-8?q?III.md?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- problems/0123.买卖股票的最佳时机III.md | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/problems/0123.买卖股票的最佳时机III.md b/problems/0123.买卖股票的最佳时机III.md index f5b95946..7286e957 100644 --- a/problems/0123.买卖股票的最佳时机III.md +++ b/problems/0123.买卖股票的最佳时机III.md @@ -442,6 +442,24 @@ impl Solution { } ``` +> 版本二(绕) + +```rust +impl Solution { + pub fn max_profit(prices: Vec) -> i32 { + let mut dp = vec![0, -prices[0], 0, -prices[0], 0]; + + for p in prices { + dp[1] = dp[1].max(-p); + dp[2] = dp[2].max(dp[1] + p); + dp[3] = dp[3].max(dp[2] - p); + dp[4] = dp[4].max(dp[3] + p); + } + dp[4] + } +} +``` +

From 2444c084b15fce271ac3639bca32bc579c594ad1 Mon Sep 17 00:00:00 2001 From: fwqaaq Date: Fri, 30 Jun 2023 11:33:23 +0800 Subject: [PATCH 014/122] =?UTF-8?q?Update=200188.=E4=B9=B0=E5=8D=96?= =?UTF-8?q?=E8=82=A1=E7=A5=A8=E7=9A=84=E6=9C=80=E4=BD=B3=E6=97=B6=E6=9C=BA?= =?UTF-8?q?IV.md=20about=20rust?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- problems/0188.买卖股票的最佳时机IV.md | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/problems/0188.买卖股票的最佳时机IV.md b/problems/0188.买卖股票的最佳时机IV.md index 5bed5ecc..8cfb4c1b 100644 --- a/problems/0188.买卖股票的最佳时机IV.md +++ b/problems/0188.买卖股票的最佳时机IV.md @@ -439,6 +439,28 @@ function maxProfit(k: number, prices: number[]): number { }; ``` +Rust: + +```rust +impl Solution { + pub fn max_profit(k: i32, prices: Vec) -> i32 { + let mut dp = vec![vec![0; 2 * k as usize + 1]; prices.len()]; + + for v in dp[0].iter_mut().skip(1).step_by(2) { + *v = -prices[0]; + } + + for (i, &p) in prices.iter().enumerate().skip(1) { + for j in (0..2 * k as usize - 1).step_by(2) { + dp[i][j + 1] = dp[i - 1][j + 1].max(dp[i - 1][j] - p); + dp[i][j + 2] = dp[i - 1][j + 2].max(dp[i - 1][j + 1] + p); + } + } + + dp[prices.len() - 1][2 * k as usize] + } +} +```

From 7d92df37eb7aca18042512789a286ec4eec3123a Mon Sep 17 00:00:00 2001 From: fwqaaq Date: Fri, 30 Jun 2023 12:36:36 +0800 Subject: [PATCH 015/122] =?UTF-8?q?Update=200309.=E6=9C=80=E4=BD=B3?= =?UTF-8?q?=E4=B9=B0=E5=8D=96=E8=82=A1=E7=A5=A8=E6=97=B6=E6=9C=BA=E5=90=AB?= =?UTF-8?q?=E5=86=B7=E5=86=BB=E6=9C=9F.md=20about=20rust?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- problems/0309.最佳买卖股票时机含冷冻期.md | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/problems/0309.最佳买卖股票时机含冷冻期.md b/problems/0309.最佳买卖股票时机含冷冻期.md index d10e61b7..cd71136b 100644 --- a/problems/0309.最佳买卖股票时机含冷冻期.md +++ b/problems/0309.最佳买卖股票时机含冷冻期.md @@ -455,7 +455,29 @@ function maxProfit(prices: number[]): number { }; ``` +Rust: +```rust +impl Solution { + pub fn max_profit(prices: Vec) -> i32 { + /* + * dp[i][0]: 持股状态; + * dp[i][1]: 无股状态,当天为非冷冻期; + * dp[i][2]: 无股状态,当天卖出; + * dp[i][3]: 无股状态,当天为冷冻期; + */ + let mut dp = vec![vec![0; 4]; prices.len()]; + dp[0][0] = -prices[0]; + for (i, &p) in prices.iter().enumerate().skip(1) { + dp[i][0] = dp[i - 1][0].max((dp[i - 1][3] - p).max(dp[i - 1][1] - p)); + dp[i][1] = dp[i - 1][1].max(dp[i - 1][3]); + dp[i][2] = dp[i - 1][0] + p; + dp[i][3] = dp[i - 1][2]; + } + *dp[prices.len() - 1].iter().skip(1).max().unwrap() + } +} +```

From e563783a71fe3de6564c7c01e8ffbfc961f3efee Mon Sep 17 00:00:00 2001 From: fwqaaq Date: Fri, 30 Jun 2023 12:52:41 +0800 Subject: [PATCH 016/122] =?UTF-8?q?Update=200714.=E4=B9=B0=E5=8D=96?= =?UTF-8?q?=E8=82=A1=E7=A5=A8=E7=9A=84=E6=9C=80=E4=BD=B3=E6=97=B6=E6=9C=BA?= =?UTF-8?q?=E5=90=AB=E6=89=8B=E7=BB=AD=E8=B4=B9=EF=BC=88=E5=8A=A8=E6=80=81?= =?UTF-8?q?=E8=A7=84=E5=88=92=EF=BC=89.md=20=E4=BC=98=E5=8C=96=20Rust?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ....买卖股票的最佳时机含手续费(动态规划).md | 31 +++++++++++++------ 1 file changed, 21 insertions(+), 10 deletions(-) diff --git a/problems/0714.买卖股票的最佳时机含手续费(动态规划).md b/problems/0714.买卖股票的最佳时机含手续费(动态规划).md index 1443f147..9aa82d4a 100644 --- a/problems/0714.买卖股票的最佳时机含手续费(动态规划).md +++ b/problems/0714.买卖股票的最佳时机含手续费(动态规划).md @@ -270,18 +270,29 @@ impl Solution { **动态规划** ```Rust impl Solution { - fn max(a: i32, b: i32) -> i32 { - if a > b { a } else { b } - } pub fn max_profit(prices: Vec, fee: i32) -> i32 { - let n = prices.len(); - let mut dp = vec![vec![0; 2]; n]; - dp[0][0] -= prices[0]; - for i in 1..n { - dp[i][0] = Self::max(dp[i - 1][0], dp[i - 1][1] - prices[i]); - dp[i][1] = Self::max(dp[i - 1][1], dp[i - 1][0] + prices[i] - fee); + let mut dp = vec![vec![0; 2]; prices.len()]; + dp[0][0] = -prices[0]; + for (i, &p) in prices.iter().enumerate().skip(1) { + dp[i][0] = dp[i - 1][0].max(dp[i - 1][1] - p); + dp[i][1] = dp[i - 1][1].max(dp[i - 1][0] + p - fee); } - Self::max(dp[n - 1][0], dp[n - 1][1]) + dp[prices.len() - 1][1] + } +} +``` + +**动态规划优化** + +```rust +impl Solution { + pub fn max_profit(prices: Vec, fee: i32) -> i32 { + let (mut low, mut res) = (-prices[0], 0); + for p in prices { + low = low.max(res - p); + res = res.max(p + low - fee); + } + res } } ``` From e452f183adde4732da370e14dc0379ebffd0bdbe Mon Sep 17 00:00:00 2001 From: fwqaaq Date: Fri, 30 Jun 2023 13:14:26 +0800 Subject: [PATCH 017/122] =?UTF-8?q?Update=200123.=E4=B9=B0=E5=8D=96?= =?UTF-8?q?=E8=82=A1=E7=A5=A8=E7=9A=84=E6=9C=80=E4=BD=B3=E6=97=B6=E6=9C=BA?= =?UTF-8?q?III.md=20=E4=BD=BF=E7=94=A8=E5=85=83=E7=A5=96=E4=BC=98=E5=8C=96?= =?UTF-8?q?=E5=91=BD=E5=90=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- problems/0123.买卖股票的最佳时机III.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/problems/0123.买卖股票的最佳时机III.md b/problems/0123.买卖股票的最佳时机III.md index 7286e957..a646b7d5 100644 --- a/problems/0123.买卖股票的最佳时机III.md +++ b/problems/0123.买卖股票的最佳时机III.md @@ -447,15 +447,15 @@ impl Solution { ```rust impl Solution { pub fn max_profit(prices: Vec) -> i32 { - let mut dp = vec![0, -prices[0], 0, -prices[0], 0]; + let (mut one_buy, mut one_sale, mut two_buy, mut two_sale) = (-prices[0], 0, -prices[0], 0); for p in prices { - dp[1] = dp[1].max(-p); - dp[2] = dp[2].max(dp[1] + p); - dp[3] = dp[3].max(dp[2] - p); - dp[4] = dp[4].max(dp[3] + p); + one_buy = one_buy.max(-p); + one_sale = one_sale.max(p + one_buy); + two_buy = two_buy.max(one_sale - p); + two_sale = two_sale.max(two_buy + p); } - dp[4] + two_sale } } ``` From 53f077dc13f8a0076c94bd7db7bbeccd4815a9ff Mon Sep 17 00:00:00 2001 From: fwqaaq Date: Fri, 30 Jun 2023 13:15:33 +0800 Subject: [PATCH 018/122] Apply suggestions from code review --- problems/0714.买卖股票的最佳时机含手续费(动态规划).md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/problems/0714.买卖股票的最佳时机含手续费(动态规划).md b/problems/0714.买卖股票的最佳时机含手续费(动态规划).md index 9aa82d4a..042de947 100644 --- a/problems/0714.买卖股票的最佳时机含手续费(动态规划).md +++ b/problems/0714.买卖股票的最佳时机含手续费(动态规划).md @@ -282,7 +282,7 @@ impl Solution { } ``` -**动态规划优化** +**动态规划空间优化** ```rust impl Solution { From c4a7033e50a8713808654ac4b179ca4883b4998f Mon Sep 17 00:00:00 2001 From: fwqaaq Date: Fri, 30 Jun 2023 13:45:44 +0800 Subject: [PATCH 019/122] =?UTF-8?q?Update=200188.=E4=B9=B0=E5=8D=96?= =?UTF-8?q?=E8=82=A1=E7=A5=A8=E7=9A=84=E6=9C=80=E4=BD=B3=E6=97=B6=E6=9C=BA?= =?UTF-8?q?IV.md?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- problems/0188.买卖股票的最佳时机IV.md | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/problems/0188.买卖股票的最佳时机IV.md b/problems/0188.买卖股票的最佳时机IV.md index 8cfb4c1b..fb1a6898 100644 --- a/problems/0188.买卖股票的最佳时机IV.md +++ b/problems/0188.买卖股票的最佳时机IV.md @@ -462,6 +462,33 @@ impl Solution { } ``` +空间优化: + +```rust +impl Solution { + pub fn max_profit(k: i32, prices: Vec) -> i32 { + let mut dp = vec![0; 2 * k as usize + 1]; + for v in dp.iter_mut().skip(1).step_by(2) { + *v = -prices[0]; + } + + for p in prices { + for i in 1..=2 * k as usize { + if i % 2 == 1 { + // 买入 + dp[i] = dp[i].max(dp[i - 1] - p); + continue; + } + // 卖出 + dp[i] = dp[i].max(dp[i - 1] + p); + } + } + + dp[2 * k as usize] + } +} +``` +

From d945a304c49f4f41de91b2794b35de0c5f79110b Mon Sep 17 00:00:00 2001 From: Binbin Date: Mon, 3 Jul 2023 19:29:44 +0800 Subject: [PATCH 020/122] =?UTF-8?q?=E9=94=99=E5=88=AB=E5=AD=97=E4=BF=AE?= =?UTF-8?q?=E5=A4=8D=EF=BC=9Arecode=20->=20record?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- problems/0383.赎金信.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/problems/0383.赎金信.md b/problems/0383.赎金信.md index e74cdf71..70501469 100644 --- a/problems/0383.赎金信.md +++ b/problems/0383.赎金信.md @@ -88,7 +88,7 @@ public: return false; } for (int i = 0; i < magazine.length(); i++) { - // 通过recode数据记录 magazine里各个字符出现次数 + // 通过record数据记录 magazine里各个字符出现次数 record[magazine[i]-'a'] ++; } for (int j = 0; j < ransomNote.length(); j++) { @@ -218,7 +218,7 @@ Go: ```go func canConstruct(ransomNote string, magazine string) bool { record := make([]int, 26) - for _, v := range magazine { // 通过recode数据记录 magazine里各个字符出现次数 + for _, v := range magazine { // 通过record数据记录 magazine里各个字符出现次数 record[v-'a']++ } for _, v := range ransomNote { // 遍历ransomNote,在record里对应的字符个数做--操作 From dacd1a91d4c4cfeeeebd77b3840118f1ba61e02d Mon Sep 17 00:00:00 2001 From: ZKkkk Date: Tue, 4 Jul 2023 19:46:00 +0800 Subject: [PATCH 021/122] =?UTF-8?q?Update=201221.=E5=88=86=E5=89=B2?= =?UTF-8?q?=E5=B9=B3=E8=A1=A1=E5=AD=97=E7=AC=A6=E4=B8=B2.md=20about=20Type?= =?UTF-8?q?Script?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- problems/1221.分割平衡字符串.md | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/problems/1221.分割平衡字符串.md b/problems/1221.分割平衡字符串.md index b587514a..2a7b0922 100644 --- a/problems/1221.分割平衡字符串.md +++ b/problems/1221.分割平衡字符串.md @@ -156,6 +156,21 @@ var balancedStringSplit = function(s) { }; ``` +### TypeScript + +```ts +function balancedStringSplit(s: string): number { + let count: number = 0 + let res: number = 0 + for(let i of s){ + if(i === 'R') count++ + else count-- + if(count === 0) res++ + } + + return res +}; +```

From d7753b31b6f66def80719e82cb7d8ddef3056a7e Mon Sep 17 00:00:00 2001 From: Liu Yongliang <41845017+tlylt@users.noreply.github.com> Date: Thu, 6 Jul 2023 23:14:49 +0800 Subject: [PATCH 022/122] =?UTF-8?q?Update=201002.=E6=9F=A5=E6=89=BE?= =?UTF-8?q?=E5=B8=B8=E7=94=A8=E5=AD=97=E7=AC=A6.md?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit fix formatting --- problems/1002.查找常用字符.md | 1 + 1 file changed, 1 insertion(+) diff --git a/problems/1002.查找常用字符.md b/problems/1002.查找常用字符.md index 9ec3c6c4..a53148b3 100644 --- a/problems/1002.查找常用字符.md +++ b/problems/1002.查找常用字符.md @@ -16,6 +16,7 @@ 输入:words = ["bella","label","roller"] 输出:["e","l","l"] + 示例 2: 输入:words = ["cool","lock","cook"] From 886287eb27b94681d578248af3ac2b348ee7e94f Mon Sep 17 00:00:00 2001 From: programmercarl <826123027@qq.com> Date: Fri, 14 Jul 2023 11:12:45 +0800 Subject: [PATCH 023/122] =?UTF-8?q?=E5=B9=B6=E6=9F=A5=E9=9B=86=E5=9B=BE?= =?UTF-8?q?=E8=AE=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- problems/图论并查集理论基础.md | 433 +++++++++++++++++++++++++++++++++ 1 file changed, 433 insertions(+) create mode 100644 problems/图论并查集理论基础.md diff --git a/problems/图论并查集理论基础.md b/problems/图论并查集理论基础.md new file mode 100644 index 00000000..5cd753e9 --- /dev/null +++ b/problems/图论并查集理论基础.md @@ -0,0 +1,433 @@ + +# 并查集理论基础 + +图论中,关于深搜和广搜我们在这里:[钥匙和房间](https://mp.weixin.qq.com/s/E9NlJy9PW1oJuD8N2EURoQ) 已经更新完毕了。 + +接下来我们来讲一下并查集,首先当然是并查集理论基础。 + +## 背景 + +首先要知道并查集可以解决什么问题呢? + +并查集常用来解决连通性问题。 + +大白话就是当我们需要判断两个元素是否在同一个集合里的时候,我们就要想到用并查集。 + +并查集主要有两个功能: + +* 将两个元素添加到一个集合中。 +* 判断两个元素在不在同一个集合 + +接下来围绕并查集的这两个功能来展开讲解。 + +## 原理讲解 + +从代码层面,我们如何将两个元素添加到同一个集合中呢。 + +此时有录友会想到:可以把他放到同一个数组里或者set 或者 map 中,这样就表述两个元素在同一个集合。 + +那么问题来了,对这些元素分门别类,可不止一个集合,可能是很多集合,成百上千,那么要定义这么多个数组吗? + +有录友想,那可以定义一个二维数组。 + +但如果我们要判断两个元素是否在同一个集合里的时候 我们又能怎么办? 只能把而二维数组都遍历一遍。 + +而且每当想添加一个元素到某集合的时候,依然需要把把二维数组组都遍历一遍,才知道要放在哪个集合里。 + +这仅仅是一个粗略的思路,如果沿着这个思路去实现代码,非常复杂,因为管理集合还需要很多逻辑。 + +那么我们来换一个思路来看看。 + +我们将三个元素A,B,C (分别是数字)放在同一个集合,其实就是将三个元素连通在一起,如何连通呢。 + +只需要用一个一维数组来表示,即:father[A] = B,father[B] = C 这样就表述 A 与 B 与 C连通了(有向连通图)。 + +代码如下: + +``` CPP +// 将v,u 这条边加入并查集 +void join(int u, int v) { + u = find(u); // 寻找u的根 + v = find(v); // 寻找v的根 + if (u == v) return; // 如果发现根相同,则说明在一个集合,不用两个节点相连直接返回 + father[v] = u; +} +``` + +可能有录友想,这样我可以知道 A 连通 B,因为 A 是索引下标,根据 father[A]的数值就知道 A 连通 B。那怎么知道 B 连通 A呢? + +我们的目的是判断这三个元素是否在同一个集合里,知道 A 连通 B 就已经足够了。 + +这里要讲到寻根思路,只要 A ,B,C 在同一个根下就是同一个集合。 + +给出A元素,就可以通过 father[A] = B,father[B] = C,找到根为 C。 + +给出B元素,就可以通过 father[B] = C,找到根也为为 C,说明 A 和 B 是在同一个集合里。 +大家会想第一段代码里find函数是如何实现的呢?其实就是通过数组下标找到数组元素,一层一层寻根过程,代码如下: + +```CPP +// 并查集里寻根的过程 +int find(int u) { + if (u == father[u]) return u; // 如果根就是自己,直接返回 + else return find(father[u]); // 如果根不是自己,就根据数组下标一层一层向下找 +} + +``` + + +如何表示 C 也在同一个元素里呢? 我们需要 father[C] = C,即C的根也为C,这样就方便表示 A,B,C 都在同一个集合里了。 + +所以father数组初始化的时候要 father[i] = i,默认自己指向自己。 + +代码如下: + +```CPP +// 并查集初始化 +void init() { + for (int i = 0; i < n; ++i) { + father[i] = i; + } +} +``` + +最后我们如何判断两个元素是否在同一个集合里,如果通过 find函数 找到 两个元素属于同一个根的话,那么这两个元素就是同一个集合,代码如下: + + +```CPP +// 判断 u 和 v是否找到同一个根 +bool isSame(int u, int v) { + u = find(u); + v = find(v); + return u == v; +} +``` + +## 路径压缩 + +在实现 find 函数的过程中,我们知道,通过递归的方式,不断获取father数组下标对应的数值,最终找到这个集合的根。 + +搜索过程像是一个多叉树中从叶子到根节点的过程,如图: + +![](https://code-thinking-1253855093.file.myqcloud.com/pics/20230602102619.png) + +如果这棵多叉树高度很深的话,每次find函数 去寻找跟的过程就要递归很多次。 + +我们的目的只需要知道这些节点在同一个根下就可以,所以对这棵多叉树的构造只需要这样就可以了,如图: + +![](https://code-thinking-1253855093.file.myqcloud.com/pics/20230602103040.png) + +除了根节点其他所有节点都挂载根节点下,这样我们在寻根的时候就很快,只需要一步, + +如果我们想达到这样的效果,就需要 **路径压缩**,将非根节点的所有节点直接指向根节点。 +那么在代码层面如何实现呢? + +我们只需要在递归的过程中,让 father[u] 接住 递归函数 find(father[u]) 的返回结果。 + +因为 find 函数向上寻找根节点,father[u] 表述 u 的父节点,那么让 father[u] 直接获取 find函数 返回的根节点,这样就让节点 u 的父节点 变成根节点。 + +代码如下,注意看注释,路径压缩就一行代码: + +```CPP +// 并查集里寻根的过程 +int find(int u) { + if (u == father[u]) return u; + else return father[u] = find(father[u]); // 路径压缩 +} +``` + +以上代码在C++中,可以用三元表达式来精简一下,代码如下: + +```CPP +int find(int u) { + return u == father[u] ? u : father[u] = find(father[u]); +} + +``` + +相信不少录友在学习并查集的时候,对上面这三行代码实现的 find函数 很熟悉,但理解上却不够深入,仅仅知道这行代码很好用,不知道这里藏着路径压缩的过程。 + +所以对于算法初学者来说,直接看精简代码学习是不太友好的,往往忽略了很多细节。 + +## 代码模板 + +那么此时并查集的模板就出来了, 整体模板C++代码如下: + +```CPP +int n = 1005; // n根据题目中节点数量而定,一般比节点数量大一点就好 +vector father = vector (n, 0); // C++里的一种数组结构 + +// 并查集初始化 +void init() { + for (int i = 0; i < n; ++i) { + father[i] = i; + } +} +// 并查集里寻根的过程 +int find(int u) { + return u == father[u] ? u : father[u] = find(father[u]); // 路径压缩 +} + +// 判断 u 和 v是否找到同一个根 +bool isSame(int u, int v) { + u = find(u); + v = find(v); + return u == v; +} + +// 将v->u 这条边加入并查集 +void join(int u, int v) { + u = find(u); // 寻找u的根 + v = find(v); // 寻找v的根 + if (u == v) return ; // 如果发现根相同,则说明在一个集合,不用两个节点相连直接返回 + father[v] = u; +} +``` +通过模板,我们可以知道,并查集主要有三个功能。 + +1. 寻找根节点,函数:find(int u),也就是判断这个节点的祖先节点是哪个 +2. 将两个节点接入到同一个集合,函数:join(int u, int v),将两个节点连在同一个根节点上 +3. 判断两个节点是否在同一个集合,函数:isSame(int u, int v),就是判断两个节点是不是同一个根节点 + +## 常见误区 + +这里估计有录友会想,模板中的 join 函数里的这段代码: + +```CPP +u = find(u); // 寻找u的根 +v = find(v); // 寻找v的根 +if (u == v) return ; // 如果发现根相同,则说明在一个集合,不用两个节点相连直接返回 + +``` + +与 isSame 函数的实现是不是重复了? 如果抽象一下呢,代码如下: + +```CPP +// 判断 u 和 v是否找到同一个根 +bool isSame(int u, int v) { + u = find(u); + v = find(v); + return u == v; +} + +// 将v->u 这条边加入并查集 +void join(int u, int v) { + if (isSame) return ; // 如果发现根相同,则说明在一个集合,不用两个节点相连直接返回 + father[v] = u; +} +``` + +这样写可以吗? 好像看出去没问题,而且代码更精简了。 + +**其实这么写是有问题的**,在join函数中 我们需要寻找 u 和 v 的根,然后再进行连线在一起,而不是直接 用 u 和 v 连线在一起。 + +举一个例子: + +``` +join(1, 2); +join(3, 2); +``` + +此时构成的图是这样的: + +![](https://code-thinking-1253855093.file.myqcloud.com/pics/20230525111307.png) + +此时问 1,3是否在同一个集合,我们调用 `join(1, 2); join(3, 2);` 很明显本意要表示 1,3是在同一个集合。 + +但我们来看一下代码逻辑,当我们调用 `isSame(1, 3)`的时候,find(1) 返回的是1,find(3)返回的是3。 `return 1 == 3` 返回的是false,代码告诉我们 1 和 3 不在同一个集合,这明显不符合我们的预期,所以问题出在哪里? + +问题出在我们精简的代码上,即 join 函数 一定要先 通过find函数寻根再进行关联。 + +如果find函数是这么实现,再来看一下逻辑过程。 + +```CPP +void join(int u, int v) { + u = find(u); // 寻找u的根 + v = find(v); // 寻找v的根 + if (u == v) return ; // 如果发现根相同,则说明在一个集合,不用两个节点相连直接返回 + father[v] = u; +} +``` + +分别将 这两对元素加入集合。 + +```CPP +join(1, 2); +join(3, 2); +``` + +当执行`join(3, 2)`的时候,会先通过find函数寻找 3的根为3,2的根为1 (第一个`join(1, 2)`,将2的根设置为1),所以最后是将1 指向 3。 + +构成的图是这样的: + +![](https://code-thinking-1253855093.file.myqcloud.com/pics/20230525112101.png) + +因为在join函数里,我们有find函数进行寻根的过程,这样就保证元素 1,2,3在这个有向图里是强连通的。 + +此时我们在调用 `isSame(1, 3)`的时候,find(1) 返回的是3,find(3) 返回的也是3,`return 3 == 3` 返回的是true,即告诉我们 元素 1 和 元素3 是 在同一个集合里的。 + + + + +## 模拟过程 + +(**凸显途径合并的过程,每一个join都要画图**) + +不少录友在接触并查集模板之后,用起来很娴熟,因为模板确实相对固定,但是对并查集内部数据组织方式以及如何判断是否是同一个集合的原理很模糊。 + +通过以上讲解之后,我在带大家一步一步去画一下,并查集内部数据连接方式。 + +注意:为了让录友们了解基础并查集的操作,不至于混乱,**以下模拟过程中不考虑路径压缩的过程**,了解基础并查集操作后,路径压缩也很容易理解。 + +我们先通过一些列的join操作,将两两元素分别放入同一个集合中。 + +```CPP +join(1, 8); +join(3, 8); +join(1, 7); +join(8, 5); +join(6, 2); +join(2, 9); + +``` + +此时我们生成的的有向图为: + +![](https://code-thinking-1253855093.file.myqcloud.com/pics/20230526122203.png) + +有录友可能想,`join(3, 8)` 在图中为什么 将 元素1 连向元素 3 而不是将 元素 8 连向 元素 3 呢? + +这一点 我在 「常见误区」标题下已经详细讲解了,因为在`join(int u, int v)`函数里 要分别对 u 和 v 寻根之后再进行关联。 + +大家看懂这个有向图后,相信应该知道如下函数的返回值了。 + +```CPP +cout << isSame(8, 7) << endl; +cout << isSame(7, 2) << endl; +``` + +返回值分别如下,表示,8 和 7 是同一个集合,而 7 和 2 不是同一个集合。 + +``` +true +false +``` + +## 拓展 + + +在「路径压缩」讲解中,我们知道如何靠压缩路径来缩短查询根节点的时间。 + +其实还有另一种方法:按秩(rank)合并。 + +rank表示树的高度,即树中结点层次的最大值。 + +例如两个集合(多叉树)需要合并,如图所示: + +![](https://code-thinking-1253855093.file.myqcloud.com/pics/20230602172250.png) + +树1 rank 为2,树2 rank 为 3。那么合并两个集合,是 树1 合入 树2,还是 树2 合入 树1呢? + +我们来看两个不同方式合入的效果。 + +![](https://code-thinking-1253855093.file.myqcloud.com/pics/20230602172933.png) + +这里可以看出,树2 合入 树1 会导致整棵树的高度变的更高,而 树1 合入 树2 整棵树的高度 和 树2 保持一致。 + +所以在 join函数中如何合并两棵树呢? + +一定是 rank 小的树合入 到 rank大 的树,这样可以保证最后合成的树rank 最小,降低在树上查询的路径长度。 + +按秩合并的代码如下: + +```CPP +int n = 1005; // n根据题目中节点数量而定,一般比节点数量大一点就好 +vector father = vector (n, 0); // C++里的一种数组结构 +vector rank = vector (n, 1); // 初始每棵树的高度都为1 + +// 并查集初始化 +void init() { + for (int i = 0; i < n; ++i) { + father[i] = i; + rank[i] = 1; // 也可以不写 + } +} +// 并查集里寻根的过程 +int find(int u) { + return u == father[u] ? u : find(father[u]);// 注意这里不做路径压缩 +} + +// 判断 u 和 v是否找到同一个根 +bool isSame(int u, int v) { + u = find(u); + v = find(v); + return u == v; +} + +// 将v->u 这条边加入并查集 +void join(int u, int v) { + u = find(u); // 寻找u的根 + v = find(v); // 寻找v的根 + + if (rank[u] <= rank[v]) father[u] = v; // rank小的树合入到rank大的树 + else father[v] = u; + + if (rank[u] == rank[v] && u != v) rank[v]++; // 如果两棵树高度相同,则v的高度+1因为,方面 if (rank[u] <= rank[v]) father[u] = v; 注意是 <= +} +``` + +可以注意到在上面的模板代码中,我是没有做路径压缩的,因为一旦做路径压缩,rank记录的高度就不准了,根据rank来判断如何合并就没有意义。 + +也可以在 路径压缩的时候,再去实时修生rank的数值,但这样在代码实现上麻烦了不少,关键是收益很小。 + +其实我们在优化并查集查询效率的时候,只用路径压缩的思路就够了,不仅代码实现精简,而且效率足够高。 + +按秩合并的思路并没有将树形结构尽可能的扁平化,所以在整理效率上是没有路径压缩高的。 + +说到这里可能有录友会想,那在路径压缩的代码中,只有查询的过程 即 find 函数的执行过程中会有路径压缩,如果一直没有使用find函数,是不是相当于这棵树就没有路径压缩,导致查询效率依然很低呢? + +大家可以再去回顾使用路径压缩的 并查集模板,在isSame函数 和 join函数中,我们都调用了 find 函数来进行寻根操作。 + +也就是说,无论使用并查集模板里哪一个函数(除了init函数),都会有路径压缩的过程,第二次访问相同节点的时候,这个节点就是直连根节点的,即 第一次访问的时候它的路径就被压缩了。 + +**所以这里推荐大家直接使用路径压缩的并查集模板就好**,但按秩合并的优化思路我依然给大家讲清楚,有助于更深一步理解并查集的优化过程。 + +## 复杂度分析 + + +这里对路径压缩版并查集来做分析。 + +空间复杂度: O(n) ,申请一个father数组。 + +关于时间复杂度,如果想精确表达出来需要繁琐的数学证明,就不在本篇讲解范围内了,大家感兴趣可以自己去深入去研究。 + +这里做一个简单的分析思路。 + +路径压缩后的并查集时间复杂度在O(logn)与O(1)之间,且随着查询或者合并操作的增加,时间复杂度会越来越趋于O(1)。 + +了解到这个程度对于求职面试来说就够了。 + +在第一次查询的时候,相当于是n叉树上从叶子节点到根节点的查询过程,时间复杂度是logn,但路径压缩后,后面的查询操作都是O(1),而 join 函数 和 isSame函数 里涉及的查询操作也是一样的过程。 + + +## 总结 + +本篇我们讲解了并查集的背景、原理、两种优化方式(路径压缩,按秩合并),代码模板,常见误区,以及模拟过程。 + +要知道并查集解决什么问题,在什么场景下我们要想到使用并查集。 + + +接下来进一步优化并查集的执行效率,重点介绍了路径压缩的方式,另一种方法:按秩合并,我们在 「拓展」中讲解。 + +通过一步一步的原理讲解,最后给出并查集的模板,所有的并查集题目都在这个模板的基础上进行操作或者适当修改。 + +但只给出模板还是不够的,针对大家学习并查集的常见误区,详细讲解了模板代码的细节。 + +为了让录友们进一步了解并查集的运行过程,我们再通过具体用例模拟一遍代码过程并画出对应的内部数据连接图(有向图)。 + +这里也建议大家去模拟一遍才能对并查集理解的更到位。 + +如果对模板代码还是有点陌生,不用担心,接下来我会讲解对应LeetCode上的并查集题目,通过一系列题目练习,大家就会感受到这套模板有多么的好用! + +敬请期待 并查集题目精讲系列。 + + From ba5ecfecaf7160911e4d464c5aecdce1f6973146 Mon Sep 17 00:00:00 2001 From: programmercarl <826123027@qq.com> Date: Fri, 14 Jul 2023 11:13:00 +0800 Subject: [PATCH 024/122] Update --- problems/0027.移除元素.md | 7 +++++-- problems/0059.螺旋矩阵II.md | 9 ++++++--- problems/0203.移除链表元素.md | 4 ++++ problems/0206.翻转链表.md | 5 +++++ problems/0209.长度最小的子数组.md | 13 ++++++++----- problems/0459.重复的子字符串.md | 16 ++++++++-------- problems/0684.冗余连接.md | 10 +++------- problems/0685.冗余连接II.md | 4 ++-- problems/0704.二分查找.md | 6 ++++-- problems/0707.设计链表.md | 8 ++++++-- problems/0977.有序数组的平方.md | 17 ++++++++++------- problems/1971.寻找图中是否存在路径.md | 6 +++--- 12 files changed, 64 insertions(+), 41 deletions(-) diff --git a/problems/0027.移除元素.md b/problems/0027.移除元素.md index 90801153..3d43a199 100644 --- a/problems/0027.移除元素.md +++ b/problems/0027.移除元素.md @@ -26,9 +26,12 @@ **你不需要考虑数组中超出新长度后面的元素。** -## 思路 -针对本题,我录制了视频讲解:[数组中移除元素并不容易!LeetCode:27. 移除元素](https://www.bilibili.com/video/BV12A4y1Z7LP),结合本题解一起看,事半功倍! +## 算法公开课 + +**[《代码随想录》算法视频公开课](https://programmercarl.com/other/gongkaike.html):[数组中移除元素并不容易!LeetCode:27. 移除元素](https://www.bilibili.com/video/BV12A4y1Z7LP),相信结合视频再看本篇题解,更有助于大家对本题的理解**。 + +## 思路 有的同学可能说了,多余的元素,删掉不就得了。 diff --git a/problems/0059.螺旋矩阵II.md b/problems/0059.螺旋矩阵II.md index b4dad9c3..fd40f3fc 100644 --- a/problems/0059.螺旋矩阵II.md +++ b/problems/0059.螺旋矩阵II.md @@ -6,7 +6,7 @@ -## 59.螺旋矩阵II +# 59.螺旋矩阵II [力扣题目链接](https://leetcode.cn/problems/spiral-matrix-ii/) @@ -22,9 +22,12 @@ [ 7, 6, 5 ] ] -## 思路 -为了利于录友们理解,我特意录制了视频,[拿下螺旋矩阵!LeetCode:59.螺旋矩阵II](https://www.bilibili.com/video/BV1SL4y1N7mV),结合视频一起看,事半功倍! +## 算法公开课 + +**[《代码随想录》算法视频公开课](https://programmercarl.com/other/gongkaike.html):[拿下螺旋矩阵!LeetCode:59.螺旋矩阵II](https://www.bilibili.com/video/BV1SL4y1N7mV),相信结合视频再看本篇题解,更有助于大家对本题的理解**。 + +## 思路 这道题目可以说在面试中出现频率较高的题目,**本题并不涉及到什么算法,就是模拟过程,但却十分考察对代码的掌控能力。** diff --git a/problems/0203.移除链表元素.md b/problems/0203.移除链表元素.md index f8751658..300f98e9 100644 --- a/problems/0203.移除链表元素.md +++ b/problems/0203.移除链表元素.md @@ -27,6 +27,10 @@ 输入:head = [7,7,7,7], val = 7 输出:[] +# 算法公开课 + +**[《代码随想录》算法视频公开课](https://programmercarl.com/other/gongkaike.html):[链表基础操作| LeetCode:203.移除链表元素](https://www.bilibili.com/video/BV18B4y1s7R9),相信结合视频再看本篇题解,更有助于大家对本题的理解**。 + # 思路 diff --git a/problems/0206.翻转链表.md b/problems/0206.翻转链表.md index 0425e182..c63c998d 100644 --- a/problems/0206.翻转链表.md +++ b/problems/0206.翻转链表.md @@ -17,6 +17,11 @@ 输入: 1->2->3->4->5->NULL 输出: 5->4->3->2->1->NULL +# 算法公开课 + +**[《代码随想录》算法视频公开课](https://programmercarl.com/other/gongkaike.html):[帮你拿下反转链表 | LeetCode:206.反转链表](https://www.bilibili.com/video/BV1nB4y1i7eL),相信结合视频再看本篇题解,更有助于大家对本题的理解**。 + + # 思路 本题我录制了B站视频,[帮你拿下反转链表 | LeetCode:206.反转链表](https://www.bilibili.com/video/BV1nB4y1i7eL),相信结合视频在看本篇题解,更有助于大家对链表的理解。 diff --git a/problems/0209.长度最小的子数组.md b/problems/0209.长度最小的子数组.md index d7ae4780..82d551ea 100644 --- a/problems/0209.长度最小的子数组.md +++ b/problems/0209.长度最小的子数组.md @@ -13,9 +13,9 @@ 示例: -输入:s = 7, nums = [2,3,1,2,4,3] -输出:2 -解释:子数组 [4,3] 是该条件下的长度最小的子数组。 +* 输入:s = 7, nums = [2,3,1,2,4,3] +* 输出:2 +* 解释:子数组 [4,3] 是该条件下的长度最小的子数组。 提示: @@ -23,9 +23,12 @@ * 1 <= nums.length <= 10^5 * 1 <= nums[i] <= 10^5 -# 思路 +# 算法公开课 -为了易于大家理解,我特意录制了B站视频[拿下滑动窗口! | LeetCode 209 长度最小的子数组](https://www.bilibili.com/video/BV1tZ4y1q7XE),结合视频看本题解,事半功倍! +**[《代码随想录》算法视频公开课](https://programmercarl.com/other/gongkaike.html):[拿下滑动窗口! | LeetCode 209 长度最小的子数组](https://www.bilibili.com/video/BV1tZ4y1q7XE),相信结合视频再看本篇题解,更有助于大家对本题的理解**。 + + +# 思路 ## 暴力解法 diff --git a/problems/0459.重复的子字符串.md b/problems/0459.重复的子字符串.md index 5d56ad18..e26d04ad 100644 --- a/problems/0459.重复的子字符串.md +++ b/problems/0459.重复的子字符串.md @@ -16,18 +16,18 @@ 给定一个非空的字符串,判断它是否可以由它的一个子串重复多次构成。给定的字符串只含有小写英文字母,并且长度不超过10000。 示例 1: -输入: "abab" -输出: True -解释: 可由子字符串 "ab" 重复两次构成。 +* 输入: "abab" +* 输出: True +* 解释: 可由子字符串 "ab" 重复两次构成。 示例 2: -输入: "aba" -输出: False +* 输入: "aba" +* 输出: False 示例 3: -输入: "abcabcabcabc" -输出: True -解释: 可由子字符串 "abc" 重复四次构成。 (或者子字符串 "abcabc" 重复两次构成。) +* 输入: "abcabcabcabc" +* 输出: True +* 解释: 可由子字符串 "abc" 重复四次构成。 (或者子字符串 "abcabc" 重复两次构成。) # 思路 diff --git a/problems/0684.冗余连接.md b/problems/0684.冗余连接.md index 177338dd..c4d62d9b 100644 --- a/problems/0684.冗余连接.md +++ b/problems/0684.冗余连接.md @@ -4,11 +4,8 @@

参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!

- - # 684.冗余连接 - [力扣题目链接](https://leetcode.cn/problems/redundant-connection/) 树可以看成是一个连通且 无环 的 无向 图。 @@ -78,7 +75,9 @@ void join(int u, int v) { 2. 将两个节点接入到同一个集合,函数:join(int u, int v),将两个节点连在同一个根节点上 3. 判断两个节点是否在同一个集合,函数:isSame(int u, int v),就是判断两个节点是不是同一个根节点 -简单介绍并查集之后,我们再来看一下这道题目。 +如果还不了解并查集,可以看这里:[并查集理论基础](https://programmercarl.com/图论并查集理论基础.html) + +我们再来看一下这道题目。 题目说是无向图,返回一条可以删去的边,使得结果图是一个有着N个节点的树(即:只有一个根节点)。 @@ -92,7 +91,6 @@ void join(int u, int v) { 节点A 和节点 B 不在同一个集合,那么就可以将两个 节点连在一起。 - (如果题目中说:如果有多个答案,则返回二维数组中最前出现的边。 那我们就要 从后向前遍历每一条边了) 如果边的两个节点已经出现在同一个集合里,说明着边的两个节点已经连在一起了,再加入这条边一定就出现环了。 @@ -151,8 +149,6 @@ public: 可以看出,主函数的代码很少,就判断一下边的两个节点在不在同一个集合就可以了。 -这里对并查集就不展开过多的讲解了,翻到了自己十年前写过了一篇并查集的文章[并查集学习](https://blog.csdn.net/youngyangyang04/article/details/6447435),哈哈,那时候还太年轻,写不咋地,有空我会重写并查集基础篇! - # 其他语言版本 diff --git a/problems/0685.冗余连接II.md b/problems/0685.冗余连接II.md index 149eab01..8c56afdc 100644 --- a/problems/0685.冗余连接II.md +++ b/problems/0685.冗余连接II.md @@ -104,7 +104,7 @@ if (vec.size() > 0) { } ``` -在来看情况三,明确没有入度为2的情况,那么一定有有向环,找到构成环的边就是要删除的边。 +在来看情况三,明确没有入度为2的情况,那么一定有向环,找到构成环的边就是要删除的边。 可以定义一个函数,代码如下: @@ -122,7 +122,7 @@ vector getRemoveEdge(const vector>& edges) **因为如果两个点所在的边在添加图之前如果就可以在并查集里找到了相同的根,那么这条边添加上之后 这个图一定不是树了** -这里对并查集就不展开过多的讲解了,翻到了自己十年前写过了一篇并查集的文章[并查集学习](https://blog.csdn.net/youngyangyang04/article/details/6447435),哈哈,那时候还太年轻,写不咋地,有空我会重写一篇! +如果还不了解并查集,可以看这里:[并查集理论基础](https://programmercarl.com/图论并查集理论基础.html) 本题C++代码如下:(详细注释了) diff --git a/problems/0704.二分查找.md b/problems/0704.二分查找.md index 75135749..c59ae868 100644 --- a/problems/0704.二分查找.md +++ b/problems/0704.二分查找.md @@ -33,11 +33,13 @@ * n 将在 [1, 10000]之间。 * nums 的每个元素都将在 [-9999, 9999]之间。 +## 算法公开课 + +***[《代码随想录》算法视频公开课](https://programmercarl.com/other/gongkaike.html):[手把手带你撕出正确的二分法](https://www.bilibili.com/video/BV1fA4y1o715),相信结合视频再看本篇题解,更有助于大家对本题的理解**。 + ## 思路 -为了易于大家理解,我还录制了视频,可以看这里:[B站:手把手带你撕出正确的二分法](https://www.bilibili.com/video/BV1fA4y1o715) - **这道题目的前提是数组为有序数组**,同时题目还强调**数组中无重复元素**,因为一旦有重复元素,使用二分查找法返回的元素下标可能不是唯一的,这些都是使用二分法的前提条件,当大家看到题目描述满足如上条件的时候,可要想一想是不是可以用二分法了。 二分查找涉及的很多的边界条件,逻辑比较简单,但就是写不好。例如到底是 `while(left < right)` 还是 `while(left <= right)`,到底是`right = middle`呢,还是要`right = middle - 1`呢? diff --git a/problems/0707.设计链表.md b/problems/0707.设计链表.md index aa04d0e1..87e5f5a9 100644 --- a/problems/0707.设计链表.md +++ b/problems/0707.设计链表.md @@ -24,9 +24,13 @@ ![707示例](https://code-thinking-1253855093.file.myqcloud.com/pics/20200814200558953.png) -# 思路 -为了方便大家理解,我特意录制了视频:[帮你把链表操作学个通透!LeetCode:707.设计链表](https://www.bilibili.com/video/BV1FU4y1X7WD),结合视频在看本题解,事半功倍。 +# 算法公开课 + +**[《代码随想录》算法视频公开课](https://programmercarl.com/other/gongkaike.html):[帮你把链表操作学个通透!LeetCode:707.设计链表](https://www.bilibili.com/video/BV1FU4y1X7WD),相信结合视频再看本篇题解,更有助于大家对本题的理解**。 + + +# 思路 如果对链表的基础知识还不太懂,可以看这篇文章:[关于链表,你该了解这些!](https://programmercarl.com/链表理论基础.html) diff --git a/problems/0977.有序数组的平方.md b/problems/0977.有序数组的平方.md index a316096e..de06c419 100644 --- a/problems/0977.有序数组的平方.md +++ b/problems/0977.有序数组的平方.md @@ -13,18 +13,21 @@ 给你一个按 非递减顺序 排序的整数数组 nums,返回 每个数字的平方 组成的新数组,要求也按 非递减顺序 排序。 示例 1: -输入:nums = [-4,-1,0,3,10] -输出:[0,1,9,16,100] -解释:平方后,数组变为 [16,1,0,9,100],排序后,数组变为 [0,1,9,16,100] +* 输入:nums = [-4,-1,0,3,10] +* 输出:[0,1,9,16,100] +* 解释:平方后,数组变为 [16,1,0,9,100],排序后,数组变为 [0,1,9,16,100] 示例 2: -输入:nums = [-7,-3,2,3,11] -输出:[4,9,9,49,121] +* 输入:nums = [-7,-3,2,3,11] +* 输出:[4,9,9,49,121] + +# 算法公开课 + +**[《代码随想录》算法视频公开课](https://programmercarl.com/other/gongkaike.html):[双指针法经典题目!LeetCode:977.有序数组的平方](https://www.bilibili.com/video/BV1QB4y1D7ep),相信结合视频再看本篇题解,更有助于大家对本题的理解**。 + # 思路 -针对本题,我录制了视频讲解:[双指针法经典题目!LeetCode:977.有序数组的平方](https://www.bilibili.com/video/BV1QB4y1D7ep),结合本题解一起看,事半功倍! - ## 暴力排序 最直观的想法,莫过于:每个数平方之后,排个序,美滋滋,代码如下: diff --git a/problems/1971.寻找图中是否存在路径.md b/problems/1971.寻找图中是否存在路径.md index 16c7cb1e..5f1d8943 100644 --- a/problems/1971.寻找图中是否存在路径.md +++ b/problems/1971.寻找图中是否存在路径.md @@ -31,9 +31,9 @@ ## 思路 -本题是并查集基础题目。 +本题是并查集基础题目。 如果还不了解并查集,可以看这里:[并查集理论基础](https://programmercarl.com/图论并查集理论基础.html) -首先要知道并查集可以解决什么问题呢? +并查集可以解决什么问题呢? 主要就是集合问题,两个节点在不在一个集合,也可以将两个节点添加到一个集合中。 @@ -70,7 +70,7 @@ void join(int u, int v) { } ``` -以上模板中,只要修改 n 大小就可以,本科n不会超过2 * 10^5。 +以上模板中,只要修改 n 大小就可以,本题n不会超过2 * 10^5。 并查集主要有三个功能。 From e5d3d1188555ea83aa00c156afcc249d4fd1fe42 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A8=8B=E5=BA=8F=E5=91=98Carl?= Date: Sun, 16 Jul 2023 20:39:00 +0800 Subject: [PATCH 025/122] =?UTF-8?q?Update=200200.=E5=B2=9B=E5=B1=BF?= =?UTF-8?q?=E6=95=B0=E9=87=8F.=E5=B9=BF=E6=90=9C=E7=89=88.md?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- problems/0200.岛屿数量.广搜版.md | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/problems/0200.岛屿数量.广搜版.md b/problems/0200.岛屿数量.广搜版.md index 2bb0973a..c20fe4f1 100644 --- a/problems/0200.岛屿数量.广搜版.md +++ b/problems/0200.岛屿数量.广搜版.md @@ -196,11 +196,8 @@ class Solution { } } ``` -

- - - -``` + +## 其他语言版本 ### Python BFS solution ```python @@ -241,3 +238,9 @@ class Solution: q.append((next_i, next_j)) visited[next_i][next_j] = True ``` + +

+ + + +``` From 3a76b3a85e097446ab5f9e7dbb6028bac81c75de Mon Sep 17 00:00:00 2001 From: jinbudaily <18336218010@163.com> Date: Mon, 17 Jul 2023 11:52:50 +0800 Subject: [PATCH 026/122] =?UTF-8?q?=E6=9B=B4=E6=96=B0=200704.=E4=BA=8C?= =?UTF-8?q?=E5=88=86=E6=9F=A5=E6=89=BE=20=E6=8E=92=E7=89=88=E6=A0=BC?= =?UTF-8?q?=E5=BC=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- problems/0704.二分查找.md | 36 ++++++++++++++++++++---------------- 1 file changed, 20 insertions(+), 16 deletions(-) diff --git a/problems/0704.二分查找.md b/problems/0704.二分查找.md index c59ae868..d202dfa1 100644 --- a/problems/0704.二分查找.md +++ b/problems/0704.二分查找.md @@ -35,7 +35,7 @@ ## 算法公开课 -***[《代码随想录》算法视频公开课](https://programmercarl.com/other/gongkaike.html):[手把手带你撕出正确的二分法](https://www.bilibili.com/video/BV1fA4y1o715),相信结合视频再看本篇题解,更有助于大家对本题的理解**。 +**[《代码随想录》算法视频公开课](https://programmercarl.com/other/gongkaike.html):[手把手带你撕出正确的二分法](https://www.bilibili.com/video/BV1fA4y1o715),相信结合视频再看本篇题解,更有助于大家对本题的理解**。 ## 思路 @@ -160,7 +160,7 @@ public: ## 其他语言版本 -**Java:** +### **Java:** (版本一)左闭右闭区间 @@ -206,7 +206,7 @@ class Solution { } ``` -**Python:** +### **Python:** (版本一)左闭右闭区间 @@ -246,7 +246,7 @@ class Solution: return -1 # 未找到目标值 ``` -**Go:** +### **Go:** (版本一)左闭右闭区间 @@ -288,7 +288,7 @@ func search(nums []int, target int) int { } ``` -**JavaScript:** +### **JavaScript:** (版本一)左闭右闭区间 [left, right] ```js @@ -345,7 +345,7 @@ var search = function(nums, target) { }; ``` -**TypeScript** +### **TypeScript** (版本一)左闭右闭区间 @@ -387,7 +387,7 @@ function search(nums: number[], target: number): number { }; ``` -**Ruby:** +### **Ruby:** ```ruby # (版本一)左闭右闭区间 @@ -425,7 +425,7 @@ def search(nums, target) end ``` -**Swift:** +### **Swift:** ```swift // (版本一)左闭右闭区间 @@ -479,7 +479,7 @@ func search(nums: [Int], target: Int) -> Int { ``` -**Rust:** +### **Rust:** ```rust # (版本一)左闭右闭区间 @@ -523,7 +523,8 @@ impl Solution { } ``` -**C:** +### **C:** + ```c // (版本一) 左闭右闭区间 [left, right] int search(int* nums, int numsSize, int target){ @@ -575,7 +576,8 @@ int search(int* nums, int numsSize, int target){ } ``` -**PHP:** +### **PHP:** + ```php // 左闭右闭区间 class Solution { @@ -607,7 +609,8 @@ class Solution { } ``` -**C#:** +### **C#:** + ```csharp //左闭右闭 public class Solution { @@ -652,7 +655,8 @@ public class Solution{ } ``` -**Kotlin:** +### **Kotlin:** + ```kotlin class Solution { fun search(nums: IntArray, target: Int): Int { @@ -682,9 +686,8 @@ class Solution { } ``` +### **Kotlin:** - -**Kotlin:** ```Kotlin // (版本一)左闭右开区间 class Solution { @@ -715,7 +718,7 @@ class Solution { } } ``` -**Scala:** +### **Scala:** (版本一)左闭右闭区间 ```scala @@ -763,3 +766,4 @@ object Solution { + From 948aca860da277d744c9fb130039fe96dd79491f Mon Sep 17 00:00:00 2001 From: jinbudaily <18336218010@163.com> Date: Mon, 17 Jul 2023 14:59:20 +0800 Subject: [PATCH 027/122] =?UTF-8?q?=E6=9B=B4=E6=96=B0=200704.=E4=BA=8C?= =?UTF-8?q?=E5=88=86=E6=9F=A5=E6=89=BE=20=E6=8E=92=E7=89=88=E6=A0=BC?= =?UTF-8?q?=E5=BC=8F=E4=BF=AE=E5=A4=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- problems/0704.二分查找.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/problems/0704.二分查找.md b/problems/0704.二分查找.md index d202dfa1..52abf578 100644 --- a/problems/0704.二分查找.md +++ b/problems/0704.二分查找.md @@ -5,7 +5,7 @@

参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!

-## 704. 二分查找 +# 704. 二分查找 [力扣题目链接](https://leetcode.cn/problems/binary-search/) @@ -766,4 +766,3 @@ object Solution { - From fdbc7442ac2b685414544f0af79d64c40da05d0f Mon Sep 17 00:00:00 2001 From: jinbudaily <18336218010@163.com> Date: Mon, 17 Jul 2023 15:11:55 +0800 Subject: [PATCH 028/122] =?UTF-8?q?=E6=9B=B4=E6=96=B0=20027.=E7=A7=BB?= =?UTF-8?q?=E9=99=A4=E5=85=83=E7=B4=A0=20=E6=8E=92=E7=89=88=E6=A0=BC?= =?UTF-8?q?=E5=BC=8F=E4=BF=AE=E5=A4=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- problems/0027.移除元素.md | 35 +++++++++++++++++++++-------------- 1 file changed, 21 insertions(+), 14 deletions(-) diff --git a/problems/0027.移除元素.md b/problems/0027.移除元素.md index 3d43a199..ce9eccf0 100644 --- a/problems/0027.移除元素.md +++ b/problems/0027.移除元素.md @@ -5,7 +5,7 @@

参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!

-## 27. 移除元素 +# 27. 移除元素 [力扣题目链接](https://leetcode.cn/problems/remove-element/) @@ -159,8 +159,8 @@ public: ## 其他语言版本 +### Java: -Java: ```java class Solution { public int removeElement(int[] nums, int val) { @@ -197,7 +197,7 @@ class Solution { } ``` -Python: +### Python: ``` python 3 @@ -233,8 +233,8 @@ class Solution: ``` +### Go: -Go: ```go func removeElement(nums []int, val int) int { length:=len(nums) @@ -275,7 +275,8 @@ func removeElement(nums []int, val int) int { } ``` -JavaScript: +### JavaScript: + ```javascript //时间复杂度:O(n) //空间复杂度:O(1) @@ -290,7 +291,7 @@ var removeElement = (nums, val) => { }; ``` -TypeScript: +### TypeScript: ```typescript function removeElement(nums: number[], val: number): number { @@ -305,7 +306,7 @@ function removeElement(nums: number[], val: number): number { }; ``` -Ruby: +### Ruby: ```ruby def remove_element(nums, val) @@ -319,7 +320,8 @@ def remove_element(nums, val) i end ``` -Rust: +### Rust: + ```rust impl Solution { pub fn remove_element(nums: &mut Vec, val: i32) -> i32 { @@ -335,7 +337,7 @@ impl Solution { } ``` -Swift: +### Swift: ```swift func removeElement(_ nums: inout [Int], _ val: Int) -> Int { @@ -351,7 +353,8 @@ func removeElement(_ nums: inout [Int], _ val: Int) -> Int { } ``` -PHP: +### PHP: + ```php class Solution { /** @@ -375,7 +378,8 @@ class Solution { } ``` -C: +### C: + ```c int removeElement(int* nums, int numsSize, int val){ int slow = 0; @@ -391,7 +395,8 @@ int removeElement(int* nums, int numsSize, int val){ } ``` -Kotlin: +### Kotlin: + ```kotlin fun removeElement(nums: IntArray, `val`: Int): Int { var slowIndex = 0 // 初始化慢指针 @@ -402,7 +407,8 @@ fun removeElement(nums: IntArray, `val`: Int): Int { } ``` -Scala: +### Scala: + ```scala object Solution { def removeElement(nums: Array[Int], `val`: Int): Int = { @@ -418,7 +424,8 @@ object Solution { } ``` -C#: +### C#: + ```csharp public class Solution { public int RemoveElement(int[] nums, int val) { From ec101bebb24b9af7910c02b979b198c238ae12b1 Mon Sep 17 00:00:00 2001 From: jinbudaily <18336218010@163.com> Date: Mon, 17 Jul 2023 15:21:00 +0800 Subject: [PATCH 029/122] =?UTF-8?q?=E6=9B=B4=E6=96=B0=200977.=E6=9C=89?= =?UTF-8?q?=E5=BA=8F=E6=95=B0=E7=BB=84=E7=9A=84=E5=B9=B3=E6=96=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- problems/0977.有序数组的平方.md | 42 ++++++++++++++++++++------------- 1 file changed, 25 insertions(+), 17 deletions(-) diff --git a/problems/0977.有序数组的平方.md b/problems/0977.有序数组的平方.md index de06c419..4bee585b 100644 --- a/problems/0977.有序数组的平方.md +++ b/problems/0977.有序数组的平方.md @@ -21,14 +21,14 @@ * 输入:nums = [-7,-3,2,3,11] * 输出:[4,9,9,49,121] -# 算法公开课 +## 算法公开课 **[《代码随想录》算法视频公开课](https://programmercarl.com/other/gongkaike.html):[双指针法经典题目!LeetCode:977.有序数组的平方](https://www.bilibili.com/video/BV1QB4y1D7ep),相信结合视频再看本篇题解,更有助于大家对本题的理解**。 -# 思路 +## 思路 -## 暴力排序 +### 暴力排序 最直观的想法,莫过于:每个数平方之后,排个序,美滋滋,代码如下: @@ -47,7 +47,7 @@ public: 这个时间复杂度是 O(n + nlogn), 可以说是O(nlogn)的时间复杂度,但为了和下面双指针法算法时间复杂度有鲜明对比,我记为 O(n + nlog n)。 -## 双指针法 +### 双指针法 数组其实是有序的, 只不过负数平方之后可能成为最大数了。 @@ -99,7 +99,8 @@ public: ## 其他语言版本 -Java: +### Java: + ```Java class Solution { public int[] sortedSquares(int[] nums) { @@ -141,7 +142,8 @@ class Solution { } ``` -Python: +### Python: + ```Python (版本一)双指针法 class Solution: @@ -176,7 +178,8 @@ class Solution: return sorted(x*x for x in nums) ``` -Go: +### Go: + ```Go func sortedSquares(nums []int) []int { n := len(nums) @@ -196,7 +199,8 @@ func sortedSquares(nums []int) []int { return ans } ``` -Rust +### Rust: + ```rust impl Solution { pub fn sorted_squares(nums: Vec) -> Vec { @@ -217,7 +221,8 @@ impl Solution { } } ``` -Javascript: +### Javascript: + ```Javascript /** * @param {number[]} nums @@ -242,7 +247,7 @@ var sortedSquares = function(nums) { }; ``` -Typescript: +### Typescript: 双指针法: @@ -277,7 +282,7 @@ function sortedSquares(nums: number[]): number[] { }; ``` -Swift: +### Swift: ```swift func sortedSquares(_ nums: [Int]) -> [Int] { @@ -305,7 +310,7 @@ func sortedSquares(_ nums: [Int]) -> [Int] { } ``` -Ruby: +### Ruby: ```ruby def sorted_squares(nums) @@ -323,8 +328,8 @@ def sorted_squares(nums) end ``` +### C: -C: ```c int* sortedSquares(int* nums, int numsSize, int* returnSize){ //返回的数组大小就是原数组大小 @@ -357,7 +362,8 @@ int* sortedSquares(int* nums, int numsSize, int* returnSize){ } ``` -PHP: +### PHP: + ```php class Solution { /** @@ -386,7 +392,7 @@ class Solution { } ``` -Kotlin: +### Kotlin: 双指针法 ```kotlin @@ -437,7 +443,7 @@ class Solution { } ``` -Scala: +### Scala: 双指针: ```scala @@ -473,7 +479,8 @@ object Solution { } ``` -C#: +### C#: + ```csharp public class Solution { public int[] SortedSquares(int[] nums) { @@ -504,3 +511,4 @@ public class Solution { + From 76c84efca0bcfab9e889bf97458dd6b6423e0f05 Mon Sep 17 00:00:00 2001 From: jinbudaily <18336218010@163.com> Date: Mon, 17 Jul 2023 15:32:24 +0800 Subject: [PATCH 030/122] =?UTF-8?q?=E6=9B=B4=E6=96=B0=200209.=20=E9=95=BF?= =?UTF-8?q?=E5=BA=A6=E6=9C=80=E5=B0=8F=E7=9A=84=E5=AD=90=E6=95=B0=E7=BB=84?= =?UTF-8?q?=20=E6=8E=92=E7=89=88=E6=A0=BC=E5=BC=8F=E4=BF=AE=E5=A4=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- problems/0209.长度最小的子数组.md | 41 +++++++++++++++++-------------- 1 file changed, 23 insertions(+), 18 deletions(-) diff --git a/problems/0209.长度最小的子数组.md b/problems/0209.长度最小的子数组.md index 82d551ea..4b1d0e96 100644 --- a/problems/0209.长度最小的子数组.md +++ b/problems/0209.长度最小的子数组.md @@ -23,14 +23,14 @@ * 1 <= nums.length <= 10^5 * 1 <= nums[i] <= 10^5 -# 算法公开课 +## 算法公开课 **[《代码随想录》算法视频公开课](https://programmercarl.com/other/gongkaike.html):[拿下滑动窗口! | LeetCode 209 长度最小的子数组](https://www.bilibili.com/video/BV1tZ4y1q7XE),相信结合视频再看本篇题解,更有助于大家对本题的理解**。 -# 思路 +## 思路 -## 暴力解法 +### 暴力解法 这道题目暴力解法当然是 两个for循环,然后不断的寻找符合条件的子序列,时间复杂度很明显是O(n^2)。 @@ -64,7 +64,7 @@ public: 后面力扣更新了数据,暴力解法已经超时了。 -## 滑动窗口 +### 滑动窗口 接下来就开始介绍数组操作中另一个重要的方法:**滑动窗口**。 @@ -151,8 +151,8 @@ public: ## 其他语言版本 +### Java: -Java: ```java class Solution { @@ -173,7 +173,7 @@ class Solution { } ``` -Python: +### Python: ```python (版本一)滑动窗口法 @@ -216,7 +216,8 @@ class Solution: return min_len if min_len != float('inf') else 0 ``` -Go: +### Go: + ```go func minSubArrayLen(target int, nums []int) int { i := 0 @@ -242,8 +243,7 @@ func minSubArrayLen(target int, nums []int) int { } ``` - -JavaScript: +### JavaScript: ```js var minSubArrayLen = function(target, nums) { @@ -266,7 +266,7 @@ var minSubArrayLen = function(target, nums) { }; ``` -Typescript: +### Typescript: ```typescript function minSubArrayLen(target: number, nums: number[]): number { @@ -288,7 +288,7 @@ function minSubArrayLen(target: number, nums: number[]): number { }; ``` -Swift: +### Swift: ```swift func minSubArrayLen(_ target: Int, _ nums: [Int]) -> Int { @@ -309,7 +309,7 @@ func minSubArrayLen(_ target: Int, _ nums: [Int]) -> Int { } ``` -Rust: +### Rust: ```rust impl Solution { @@ -336,7 +336,8 @@ impl Solution { } ``` -PHP: +### PHP: + ```php // 双指针 - 滑动窗口 class Solution { @@ -365,7 +366,7 @@ class Solution { } ``` -Ruby: +### Ruby: ```ruby def min_sub_array_len(target, nums) @@ -383,8 +384,9 @@ def min_sub_array_len(target, nums) end ``` -C: +### C: 暴力解法: + ```c int minSubArrayLen(int target, int* nums, int numsSize){ //初始化最小长度为INT_MAX @@ -433,7 +435,8 @@ int minSubArrayLen(int target, int* nums, int numsSize){ } ``` -Kotlin: +### Kotlin: + ```kotlin class Solution { fun minSubArrayLen(target: Int, nums: IntArray): Int { @@ -485,7 +488,7 @@ class Solution { } } ``` -Scala: +### Scala: 滑动窗口: ```scala @@ -533,7 +536,8 @@ object Solution { } } ``` -C#: +### C#: + ```csharp public class Solution { public int MinSubArrayLen(int s, int[] nums) { @@ -559,3 +563,4 @@ public class Solution { + From 7a30d500cb5f328c3e4c952f2f9ae0ecb3382b45 Mon Sep 17 00:00:00 2001 From: jinbudaily <18336218010@163.com> Date: Mon, 17 Jul 2023 15:47:48 +0800 Subject: [PATCH 031/122] =?UTF-8?q?=E6=9B=B4=E6=96=B0=20059.=E8=9E=BA?= =?UTF-8?q?=E6=97=8B=E7=9F=A9=E9=98=B5II=20=E6=8E=92=E7=89=88=E6=A0=BC?= =?UTF-8?q?=E5=BC=8F=E4=BF=AE=E5=A4=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- problems/0059.螺旋矩阵II.md | 33 +++++++++++++++++++-------------- 1 file changed, 19 insertions(+), 14 deletions(-) diff --git a/problems/0059.螺旋矩阵II.md b/problems/0059.螺旋矩阵II.md index fd40f3fc..f03fcdad 100644 --- a/problems/0059.螺旋矩阵II.md +++ b/problems/0059.螺旋矩阵II.md @@ -26,7 +26,7 @@ ## 算法公开课 **[《代码随想录》算法视频公开课](https://programmercarl.com/other/gongkaike.html):[拿下螺旋矩阵!LeetCode:59.螺旋矩阵II](https://www.bilibili.com/video/BV1SL4y1N7mV),相信结合视频再看本篇题解,更有助于大家对本题的理解**。 - + ## 思路 这道题目可以说在面试中出现频率较高的题目,**本题并不涉及到什么算法,就是模拟过程,但却十分考察对代码的掌控能力。** @@ -125,15 +125,15 @@ public: ## 类似题目 -* 54.螺旋矩阵 -* 剑指Offer 29.顺时针打印矩阵 +* [54.螺旋矩阵](https://leetcode.cn/problems/spiral-matrix/) +* [剑指Offer 29.顺时针打印矩阵](https://leetcode.cn/problems/shun-shi-zhen-da-yin-ju-zhen-lcof/) ## 其他语言版本 -Java: +### Java: ```Java class Solution { @@ -176,7 +176,7 @@ class Solution { } ``` -python3: +### python3: ```python class Solution: @@ -207,7 +207,7 @@ class Solution: return nums ``` -javaScript +### JavaScript: ```javascript @@ -259,7 +259,7 @@ var generateMatrix = function(n) { ``` -TypeScript: +### TypeScript: ```typescript function generateMatrix(n: number): number[][] { @@ -304,7 +304,7 @@ function generateMatrix(n: number): number[][] { }; ``` -Go: +### Go: ```go package main @@ -397,7 +397,7 @@ func generateMatrix(n int) [][]int { } ``` -Swift: +### Swift: ```swift func generateMatrix(_ n: Int) -> [[Int]] { @@ -453,7 +453,7 @@ func generateMatrix(_ n: Int) -> [[Int]] { } ``` -Rust: +### Rust: ```rust impl Solution { @@ -506,7 +506,8 @@ impl Solution { } ``` -PHP: +### PHP: + ```php class Solution { /** @@ -548,7 +549,8 @@ class Solution { } ``` -C: +### C: + ```c int** generateMatrix(int n, int* returnSize, int** returnColumnSizes){ //初始化返回的结果数组的大小 @@ -607,7 +609,8 @@ int** generateMatrix(int n, int* returnSize, int** returnColumnSizes){ return ans; } ``` -Scala: +### Scala: + ```scala object Solution { def generateMatrix(n: Int): Array[Array[Int]] = { @@ -659,7 +662,8 @@ object Solution { } } ``` -C#: +### C#: + ```csharp public class Solution { public int[][] GenerateMatrix(int n) { @@ -688,3 +692,4 @@ public class Solution { + From 053632c31d05cae6391b29db2ec76f1945eb2cfe Mon Sep 17 00:00:00 2001 From: jinbudaily <18336218010@163.com> Date: Mon, 17 Jul 2023 15:51:53 +0800 Subject: [PATCH 032/122] =?UTF-8?q?=E6=9B=B4=E6=96=B0=20=E6=95=B0=E7=BB=84?= =?UTF-8?q?=E6=80=BB=E7=BB=93=E7=AF=87=20=E6=8E=92=E7=89=88=E6=A0=BC?= =?UTF-8?q?=E5=BC=8F=E4=BF=AE=E5=A4=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- problems/数组总结篇.md | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/problems/数组总结篇.md b/problems/数组总结篇.md index ef962187..7550ce02 100644 --- a/problems/数组总结篇.md +++ b/problems/数组总结篇.md @@ -4,9 +4,9 @@

参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!

+# 数组总结篇 - -# 数组理论基础 +## 数组理论基础 数组是非常基础的数据结构,在面试中,考察数组的题目一般在思维上都不难,主要是考察对代码的掌控能力 @@ -51,7 +51,7 @@ 所以**Java的二维数组在内存中不是 `3*4` 的连续地址空间,而是四条连续的地址空间组成!** -# 数组的经典题目 +## 数组的经典题目 在面试中,数组是必考的基础数据结构。 @@ -59,7 +59,7 @@ 我们之前一共讲解了四道经典数组题目,每一道题目都代表一个类型,一种思想。 -## 二分法 +### 二分法 [数组:每次遇到二分法,都是一看就会,一写就废](https://programmercarl.com/0704.二分查找.html) @@ -75,7 +75,7 @@ **二分法是算法面试中的常考题,建议通过这道题目,锻炼自己手撕二分的能力**。 -## 双指针法 +### 双指针法 * [数组:就移除个元素很难么?](https://programmercarl.com/0027.移除元素.html) @@ -91,7 +91,7 @@ 双指针法(快慢指针法)在数组和链表的操作中是非常常见的,很多考察数组和链表操作的面试题,都使用双指针法。 -## 滑动窗口 +### 滑动窗口 * [数组:滑动窗口拯救了你](https://programmercarl.com/0209.长度最小的子数组.html) @@ -107,7 +107,7 @@ 如果没有接触过这一类的方法,很难想到类似的解题思路,滑动窗口方法还是很巧妙的。 -## 模拟行为 +### 模拟行为 * [数组:这个循环可以转懵很多人!](https://programmercarl.com/0059.螺旋矩阵II.html) @@ -118,7 +118,7 @@ 相信大家有遇到过这种情况: 感觉题目的边界调节超多,一波接着一波的判断,找边界,拆了东墙补西墙,好不容易运行通过了,代码写的十分冗余,毫无章法,其实**真正解决题目的代码都是简洁的,或者有原则性的**,大家可以在这道题目中体会到这一点。 -# 总结 +## 总结 ![](https://code-thinking-1253855093.file.myqcloud.com/pics/数组总结.png) From a3cc34ef7413e7e80420674bd261e4de393f152c Mon Sep 17 00:00:00 2001 From: jinbudaily <18336218010@163.com> Date: Mon, 17 Jul 2023 15:53:46 +0800 Subject: [PATCH 033/122] =?UTF-8?q?=E6=9B=B4=E6=96=B0=20=E6=95=B0=E7=BB=84?= =?UTF-8?q?=E7=90=86=E8=AE=BA=E5=9F=BA=E7=A1=80=20=E6=8E=92=E7=89=88?= =?UTF-8?q?=E6=A0=BC=E5=BC=8F=E4=BF=AE=E5=A4=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- problems/数组理论基础.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/problems/数组理论基础.md b/problems/数组理论基础.md index 67b7b20d..d104c883 100644 --- a/problems/数组理论基础.md +++ b/problems/数组理论基础.md @@ -6,7 +6,7 @@ -## 数组理论基础 +# 数组理论基础 数组是非常基础的数据结构,在面试中,考察数组的题目一般在思维上都不难,主要是考察对代码的掌控能力 From b51a1d89bf6b340f3a96ba7f109c1d481a887693 Mon Sep 17 00:00:00 2001 From: jinbudaily <18336218010@163.com> Date: Tue, 18 Jul 2023 14:21:20 +0800 Subject: [PATCH 034/122] =?UTF-8?q?=E6=9B=B4=E6=96=B0=20=E9=93=BE=E8=A1=A8?= =?UTF-8?q?=E7=90=86=E8=AE=BA=E5=9F=BA=E7=A1=80=20=E6=8E=92=E7=89=88?= =?UTF-8?q?=E6=A0=BC=E5=BC=8F=E4=BF=AE=E5=A4=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- problems/链表理论基础.md | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/problems/链表理论基础.md b/problems/链表理论基础.md index a09974df..da5a1b02 100644 --- a/problems/链表理论基础.md +++ b/problems/链表理论基础.md @@ -16,15 +16,15 @@ 如图所示: ![链表1](https://code-thinking-1253855093.file.myqcloud.com/pics/20200806194529815.png) -# 链表的类型 +## 链表的类型 接下来说一下链表的几种类型: -## 单链表 +### 单链表 刚刚说的就是单链表。 -## 双链表 +### 双链表 单链表中的指针域只能指向节点的下一个节点。 @@ -35,7 +35,7 @@ 如图所示: ![链表2](https://code-thinking-1253855093.file.myqcloud.com/pics/20200806194559317.png) -## 循环链表 +### 循环链表 循环链表,顾名思义,就是链表首尾相连。 @@ -44,7 +44,7 @@ ![链表4](https://code-thinking-1253855093.file.myqcloud.com/pics/20200806194629603.png) -# 链表的存储方式 +## 链表的存储方式 了解完链表的类型,再来说一说链表在内存中的存储方式。 @@ -60,7 +60,7 @@ 这个链表起始节点为2, 终止节点为7, 各个节点分布在内存的不同地址空间上,通过指针串联在一起。 -# 链表的定义 +## 链表的定义 接下来说一说链表的定义。 @@ -100,9 +100,9 @@ head->val = 5; 所以如果不定义构造函数使用默认构造函数的话,在初始化的时候就不能直接给变量赋值! -# 链表的操作 +## 链表的操作 -## 删除节点 +### 删除节点 删除D节点,如图所示: @@ -116,7 +116,7 @@ head->val = 5; 其他语言例如Java、Python,就有自己的内存回收机制,就不用自己手动释放了。 -## 添加节点 +### 添加节点 如图所示: @@ -126,7 +126,7 @@ head->val = 5; 但是要注意,要是删除第五个节点,需要从头节点查找到第四个节点通过next指针进行删除操作,查找的时间复杂度是O(n)。 -# 性能分析 +## 性能分析 再把链表的特性和数组的特性进行一个对比,如图所示: @@ -143,8 +143,7 @@ head->val = 5; ## 其他语言版本 - -Java: +### Java: ```java public class ListNode { @@ -171,7 +170,7 @@ public class ListNode { } ``` -JavaScript: +### JavaScript: ```javascript class ListNode { @@ -184,7 +183,7 @@ class ListNode { } ``` -TypeScript: +### TypeScript: ```typescript class ListNode { @@ -197,7 +196,7 @@ class ListNode { } ``` -Python: +### Python: ```python class ListNode: @@ -206,7 +205,7 @@ class ListNode: self.next = next ``` -Go: +### Go: ```go type ListNode struct { @@ -215,7 +214,7 @@ type ListNode struct { } ``` -Scala: +### Scala: ```scala class ListNode(_x: Int = 0, _next: ListNode = null) { @@ -224,7 +223,7 @@ class ListNode(_x: Int = 0, _next: ListNode = null) { } ``` -Rust: +### Rust: ```rust #[derive(PartialEq, Eq, Clone, Debug)] @@ -246,3 +245,4 @@ impl ListNode { + From a78116889f705d9e7f72f927decb0a9e844bd807 Mon Sep 17 00:00:00 2001 From: jinbudaily <18336218010@163.com> Date: Tue, 18 Jul 2023 14:28:12 +0800 Subject: [PATCH 035/122] =?UTF-8?q?=E6=9B=B4=E6=96=B0=200203.=E7=A7=BB?= =?UTF-8?q?=E9=99=A4=E9=93=BE=E8=A1=A8=E5=85=83=E7=B4=A0=20=E6=8E=92?= =?UTF-8?q?=E7=89=88=E6=A0=BC=E5=BC=8F=E4=BF=AE=E5=A4=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- problems/0203.移除链表元素.md | 33 ++++++++++++++++----------------- 1 file changed, 16 insertions(+), 17 deletions(-) diff --git a/problems/0203.移除链表元素.md b/problems/0203.移除链表元素.md index 300f98e9..f09c572b 100644 --- a/problems/0203.移除链表元素.md +++ b/problems/0203.移除链表元素.md @@ -27,14 +27,12 @@ 输入:head = [7,7,7,7], val = 7 输出:[] -# 算法公开课 +## 算法公开课 **[《代码随想录》算法视频公开课](https://programmercarl.com/other/gongkaike.html):[链表基础操作| LeetCode:203.移除链表元素](https://www.bilibili.com/video/BV18B4y1s7R9),相信结合视频再看本篇题解,更有助于大家对本题的理解**。 -# 思路 - -为了方便大家理解,我特意录制了视频:[链表基础操作| LeetCode:203.移除链表元素](https://www.bilibili.com/video/BV18B4y1s7R9),结合视频在看本题解,事半功倍。 +## 思路 这里以链表 1 4 2 4 来举例,移除元素4。 @@ -91,7 +89,7 @@ 最后呢在题目中,return 头结点的时候,别忘了 `return dummyNode->next;`, 这才是新的头结点 -# C++代码 +### C++代码 **直接使用原来的链表来进行移除节点操作:** @@ -159,7 +157,7 @@ public: ## 其他语言版本 -C: +### C: 用原来的链表操作: ```c @@ -227,7 +225,7 @@ struct ListNode* removeElements(struct ListNode* head, int val){ } ``` -Java: +### Java: ```java /** @@ -308,7 +306,7 @@ public ListNode removeElements(ListNode head, int val) { } ``` -Python: +### Python: ```python (版本一)虚拟头节点法 @@ -334,7 +332,7 @@ class Solution: ``` -Go: +### Go: ```go /** @@ -359,7 +357,7 @@ func removeElements(head *ListNode, val int) *ListNode { } ``` -javaScript: +### JavaScript: ```js /** @@ -381,7 +379,7 @@ var removeElements = function(head, val) { }; ``` -TypeScript: +### TypeScript: 版本一(在原链表上直接删除): @@ -437,7 +435,7 @@ function removeElements(head: ListNode | null, val: number): ListNode | null { }; ``` -Swift: +### Swift: ```swift /** @@ -465,7 +463,7 @@ func removeElements(_ head: ListNode?, _ val: Int) -> ListNode? { } ``` -PHP: +### PHP: ```php /** @@ -493,7 +491,7 @@ func removeElements(head *ListNode, val int) *ListNode { } ``` -RUST: +### Rust: ```rust // Definition for singly-linked list. @@ -531,7 +529,7 @@ impl Solution { } ``` -Scala: +### Scala: ```scala /** @@ -564,7 +562,7 @@ object Solution { } ``` -Kotlin: +### Kotlin: ```kotlin /** @@ -600,7 +598,8 @@ class Solution { } ``` -C# +### C# + ```CSharp /** * Definition for singly-linked list. From 61366ff59037d5f22f256e5bc410efd8a36a35d3 Mon Sep 17 00:00:00 2001 From: jinbudaily <18336218010@163.com> Date: Tue, 18 Jul 2023 14:41:02 +0800 Subject: [PATCH 036/122] =?UTF-8?q?=E6=9B=B4=E6=96=B0=200707.=E8=AE=BE?= =?UTF-8?q?=E8=AE=A1=E9=93=BE=E8=A1=A8=20=E6=8E=92=E7=89=88=E6=A0=BC?= =?UTF-8?q?=E5=BC=8F=E4=BF=AE=E5=A4=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- problems/0203.移除链表元素.md | 4 +--- problems/0707.设计链表.md | 34 ++++++++++++++++++---------------- 2 files changed, 19 insertions(+), 19 deletions(-) diff --git a/problems/0203.移除链表元素.md b/problems/0203.移除链表元素.md index f09c572b..c8f802a1 100644 --- a/problems/0203.移除链表元素.md +++ b/problems/0203.移除链表元素.md @@ -88,9 +88,6 @@ 最后呢在题目中,return 头结点的时候,别忘了 `return dummyNode->next;`, 这才是新的头结点 - -### C++代码 - **直接使用原来的链表来进行移除节点操作:** ```CPP @@ -638,3 +635,4 @@ public class Solution + diff --git a/problems/0707.设计链表.md b/problems/0707.设计链表.md index 3f096a22..c27f0107 100644 --- a/problems/0707.设计链表.md +++ b/problems/0707.设计链表.md @@ -25,12 +25,12 @@ ![707示例](https://code-thinking-1253855093.file.myqcloud.com/pics/20200814200558953.png) -# 算法公开课 +## 算法公开课 **[《代码随想录》算法视频公开课](https://programmercarl.com/other/gongkaike.html):[帮你把链表操作学个通透!LeetCode:707.设计链表](https://www.bilibili.com/video/BV1FU4y1X7WD),相信结合视频再看本篇题解,更有助于大家对本题的理解**。 -# 思路 +## 思路 如果对链表的基础知识还不太懂,可以看这篇文章:[关于链表,你该了解这些!](https://programmercarl.com/链表理论基础.html) @@ -58,8 +58,6 @@ 下面采用的设置一个虚拟头结点(这样更方便一些,大家看代码就会感受出来)。 - -## 代码 ```CPP class MyLinkedList { public: @@ -167,7 +165,8 @@ private: ## 其他语言版本 -C: +### C: + ```C typedef struct MyLinkedList { int val; @@ -291,7 +290,8 @@ void myLinkedListFree(MyLinkedList* obj) { */ ``` -Java: +### Java: + ```Java //单链表 class ListNode { @@ -487,7 +487,8 @@ class MyLinkedList { */ ``` -Python: +### Python: + ```python (版本一)单链表法 class ListNode: @@ -661,7 +662,7 @@ class MyLinkedList: # obj.deleteAtIndex(index) ``` -Go: +### Go: ```go //单链表实现 @@ -915,7 +916,7 @@ func (this *MyLinkedList) DeleteAtIndex(index int) { } ``` -javaScript: +### JavaScript: ```js @@ -1055,7 +1056,8 @@ MyLinkedList.prototype.deleteAtIndex = function(index) { */ ``` -TypeScript: +### TypeScript: + ```TypeScript class ListNode { public val: number; @@ -1173,7 +1175,8 @@ class MyLinkedList { } ``` -Kotlin: +### Kotlin: + ```kotlin class MyLinkedList { @@ -1241,8 +1244,7 @@ class MyLinkedList { } ``` - -Swift: +### Swift: ```swift class MyLinkedList { @@ -1323,7 +1325,8 @@ class MyLinkedList { } ``` -Scala: +### Scala: + ```scala class ListNode(_x: Int = 0, _next: ListNode = null) { var next: ListNode = _next @@ -1393,7 +1396,7 @@ class MyLinkedList() { } ``` -Rust: +### Rust: ```rust #[derive(Debug)] @@ -1486,4 +1489,3 @@ impl MyLinkedList { - From 32bf073bc8c2fe08aabc9aaf0ef61184febfb0a8 Mon Sep 17 00:00:00 2001 From: jinbudaily <18336218010@163.com> Date: Tue, 18 Jul 2023 14:50:44 +0800 Subject: [PATCH 037/122] =?UTF-8?q?=E6=9B=B4=E6=96=B0=200206.=E5=8F=8D?= =?UTF-8?q?=E8=BD=AC=E9=93=BE=E8=A1=A8=20=E6=8E=92=E7=89=88=E6=A0=BC?= =?UTF-8?q?=E5=BC=8F=E4=BF=AE=E5=A4=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- problems/0206.反转链表.md | 745 ++++++++++++++++++++++++++++++++++++++ problems/0206.翻转链表.md | 55 ++- 2 files changed, 772 insertions(+), 28 deletions(-) create mode 100644 problems/0206.反转链表.md diff --git a/problems/0206.反转链表.md b/problems/0206.反转链表.md new file mode 100644 index 00000000..5a57939a --- /dev/null +++ b/problems/0206.反转链表.md @@ -0,0 +1,745 @@ +

+ + + +

参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!

+ + +> 反转链表的写法很简单,一些同学甚至可以背下来但过一阵就忘了该咋写,主要是因为没有理解真正的反转过程。 + +# 206.反转链表 + +[力扣题目链接](https://leetcode.cn/problems/reverse-linked-list/) + +题意:反转一个单链表。 + +示例: +输入: 1->2->3->4->5->NULL +输出: 5->4->3->2->1->NULL + +## 算法公开课 + +**[《代码随想录》算法视频公开课](https://programmercarl.com/other/gongkaike.html):[帮你拿下反转链表 | LeetCode:206.反转链表](https://www.bilibili.com/video/BV1nB4y1i7eL),相信结合视频再看本篇题解,更有助于大家对本题的理解**。 + + +## 思路 + +如果再定义一个新的链表,实现链表元素的反转,其实这是对内存空间的浪费。 + +其实只需要改变链表的next指针的指向,直接将链表反转 ,而不用重新定义一个新的链表,如图所示: + + +![206_反转链表](https://code-thinking-1253855093.file.myqcloud.com/pics/20210218090901207.png) + +之前链表的头节点是元素1, 反转之后头结点就是元素5 ,这里并没有添加或者删除节点,仅仅是改变next指针的方向。 + +那么接下来看一看是如何反转的呢? + +我们拿有示例中的链表来举例,如动画所示:(纠正:动画应该是先移动pre,在移动cur) + +![](https://code-thinking.cdn.bcebos.com/gifs/206.%E7%BF%BB%E8%BD%AC%E9%93%BE%E8%A1%A8.gif) + +首先定义一个cur指针,指向头结点,再定义一个pre指针,初始化为null。 + +然后就要开始反转了,首先要把 cur->next 节点用tmp指针保存一下,也就是保存一下这个节点。 + +为什么要保存一下这个节点呢,因为接下来要改变 cur->next 的指向了,将cur->next 指向pre ,此时已经反转了第一个节点了。 + +接下来,就是循环走如下代码逻辑了,继续移动pre和cur指针。 + +最后,cur 指针已经指向了null,循环结束,链表也反转完毕了。 此时我们return pre指针就可以了,pre指针就指向了新的头结点。 + +### 双指针法 +```CPP +class Solution { +public: + ListNode* reverseList(ListNode* head) { + ListNode* temp; // 保存cur的下一个节点 + ListNode* cur = head; + ListNode* pre = NULL; + while(cur) { + temp = cur->next; // 保存一下 cur的下一个节点,因为接下来要改变cur->next + cur->next = pre; // 翻转操作 + // 更新pre 和 cur指针 + pre = cur; + cur = temp; + } + return pre; + } +}; +``` + +* 时间复杂度: O(n) +* 空间复杂度: O(1) + +### 递归法 + +递归法相对抽象一些,但是其实和双指针法是一样的逻辑,同样是当cur为空的时候循环结束,不断将cur指向pre的过程。 + +关键是初始化的地方,可能有的同学会不理解, 可以看到双指针法中初始化 cur = head,pre = NULL,在递归法中可以从如下代码看出初始化的逻辑也是一样的,只不过写法变了。 + +具体可以看代码(已经详细注释),**双指针法写出来之后,理解如下递归写法就不难了,代码逻辑都是一样的。** +```CPP +class Solution { +public: + ListNode* reverse(ListNode* pre,ListNode* cur){ + if(cur == NULL) return pre; + ListNode* temp = cur->next; + cur->next = pre; + // 可以和双指针法的代码进行对比,如下递归的写法,其实就是做了这两步 + // pre = cur; + // cur = temp; + return reverse(cur,temp); + } + ListNode* reverseList(ListNode* head) { + // 和双指针法初始化是一样的逻辑 + // ListNode* cur = head; + // ListNode* pre = NULL; + return reverse(NULL, head); + } + +}; +``` + +* 时间复杂度: O(n), 要递归处理链表的每个节点 +* 空间复杂度: O(n), 递归调用了 n 层栈空间 + +我们可以发现,上面的递归写法和双指针法实质上都是从前往后翻转指针指向,其实还有另外一种与双指针法不同思路的递归写法:从后往前翻转指针指向。 + +具体代码如下(带详细注释): + +```CPP +class Solution { +public: + ListNode* reverseList(ListNode* head) { + // 边缘条件判断 + if(head == NULL) return NULL; + if (head->next == NULL) return head; + + // 递归调用,翻转第二个节点开始往后的链表 + ListNode *last = reverseList(head->next); + // 翻转头节点与第二个节点的指向 + head->next->next = head; + // 此时的 head 节点为尾节点,next 需要指向 NULL + head->next = NULL; + return last; + } +}; +``` + +* 时间复杂度: O(n) +* 空间复杂度: O(n) + + +## 其他语言版本 + +### Java: + +```java +// 双指针 +class Solution { + public ListNode reverseList(ListNode head) { + ListNode prev = null; + ListNode cur = head; + ListNode temp = null; + while (cur != null) { + temp = cur.next;// 保存下一个节点 + cur.next = prev; + prev = cur; + cur = temp; + } + return prev; + } +} +``` + +```java +// 递归 +class Solution { + public ListNode reverseList(ListNode head) { + return reverse(null, head); + } + + private ListNode reverse(ListNode prev, ListNode cur) { + if (cur == null) { + return prev; + } + ListNode temp = null; + temp = cur.next;// 先保存下一个节点 + cur.next = prev;// 反转 + // 更新prev、cur位置 + // prev = cur; + // cur = temp; + return reverse(cur, temp); + } +} +``` + +```java +// 从后向前递归 +class Solution { + ListNode reverseList(ListNode head) { + // 边缘条件判断 + if(head == null) return null; + if (head.next == null) return head; + + // 递归调用,翻转第二个节点开始往后的链表 + ListNode last = reverseList(head.next); + // 翻转头节点与第二个节点的指向 + head.next.next = head; + // 此时的 head 节点为尾节点,next 需要指向 NULL + head.next = null; + return last; + } +} +``` + +### Python: + +```python +(版本一)双指针法 +# Definition for singly-linked list. +# class ListNode: +# def __init__(self, val=0, next=None): +# self.val = val +# self.next = next +class Solution: + def reverseList(self, head: ListNode) -> ListNode: + cur = head + pre = None + while cur: + temp = cur.next # 保存一下 cur的下一个节点,因为接下来要改变cur->next + cur.next = pre #反转 + #更新pre、cur指针 + pre = cur + cur = temp + return pre +``` + +```python +(版本二)递归法 +# Definition for singly-linked list. +# class ListNode: +# def __init__(self, val=0, next=None): +# self.val = val +# self.next = next +class Solution: + def reverseList(self, head: ListNode) -> ListNode: + return self.reverse(head, None) + def reverse(self, cur: ListNode, pre: ListNode) -> ListNode: + if cur == None: + return pre + temp = cur.next + cur.next = pre + return self.reverse(temp, cur) + +``` + + + +### Go: + +```go +//双指针 +func reverseList(head *ListNode) *ListNode { + var pre *ListNode + cur := head + for cur != nil { + next := cur.Next + cur.Next = pre + pre = cur + cur = next + } + return pre +} + +//递归 +func reverseList(head *ListNode) *ListNode { + return help(nil, head) +} + +func help(pre, head *ListNode)*ListNode{ + if head == nil { + return pre + } + next := head.Next + head.Next = pre + return help(head, next) +} + +``` +### JavaScript: + +```js +/** + * @param {ListNode} head + * @return {ListNode} + */ + +// 双指针: +var reverseList = function(head) { + if(!head || !head.next) return head; + let temp = null, pre = null, cur = head; + while(cur) { + temp = cur.next; + cur.next = pre; + pre = cur; + cur = temp; + } + // temp = cur = null; + return pre; +}; + +// 递归: +var reverse = function(pre, head) { + if(!head) return pre; + const temp = head.next; + head.next = pre; + pre = head + return reverse(pre, temp); +} + +var reverseList = function(head) { + return reverse(null, head); +}; + +// 递归2 +var reverse = function(head) { + if(!head || !head.next) return head; + // 从后往前翻 + const pre = reverse(head.next); + head.next = pre.next; + pre.next = head; + return head; +} + +var reverseList = function(head) { + let cur = head; + while(cur && cur.next) { + cur = cur.next; + } + reverse(head); + return cur; +}; +``` + +### TypeScript: + +```typescript +// 双指针法 +function reverseList(head: ListNode | null): ListNode | null { + let preNode: ListNode | null = null, + curNode: ListNode | null = head, + tempNode: ListNode | null; + while (curNode) { + tempNode = curNode.next; + curNode.next = preNode; + preNode = curNode; + curNode = tempNode; + } + return preNode; +}; + +// 递归(从前往后翻转) +function reverseList(head: ListNode | null): ListNode | null { + function recur(preNode: ListNode | null, curNode: ListNode | null): ListNode | null { + if (curNode === null) return preNode; + let tempNode: ListNode | null = curNode.next; + curNode.next = preNode; + preNode = curNode; + curNode = tempNode; + return recur(preNode, curNode); + } + return recur(null, head); +}; + +// 递归(从后往前翻转) +function reverseList(head: ListNode | null): ListNode | null { + if (head === null) return null; + let newHead: ListNode | null; + function recur(node: ListNode | null, preNode: ListNode | null): void { + if (node.next === null) { + newHead = node; + newHead.next = preNode; + } else { + recur(node.next, node); + node.next = preNode; + } + } + recur(head, null); + return newHead; +}; +``` + +### Ruby: + +```ruby +# 双指针 +# Definition for singly-linked list. +# class ListNode +# attr_accessor :val, :next +# def initialize(val = 0, _next = nil) +# @val = val +# @next = _next +# end +# end +def reverse_list(head) + # return nil if head.nil? # 循环判断条件亦能起到相同作用因此不必单独判断 + cur, per = head, nil + until cur.nil? + tem = cur.next + cur.next = per + per = cur + cur = tem + end + per +end + +# 递归 +# Definition for singly-linked list. +# class ListNode +# attr_accessor :val, :next +# def initialize(val = 0, _next = nil) +# @val = val +# @next = _next +# end +# end +def reverse_list(head) + reverse(nil, head) +end + +def reverse(pre, cur) + return pre if cur.nil? + tem = cur.next + cur.next = pre + reverse(cur, tem) # 通过递归实现双指针法中的更新操作 +end +``` + +### Kotlin: + +```Kotlin +fun reverseList(head: ListNode?): ListNode? { + var pre: ListNode? = null + var cur = head + while (cur != null) { + val temp = cur.next + cur.next = pre + pre = cur + cur = temp + } + return pre +} +``` +```kotlin +/** + * Example: + * var li = ListNode(5) + * var v = li.`val` + * Definition for singly-linked list. + * class ListNode(var `val`: Int) { + * var next: ListNode? = null + * } + */ +class Solution { + fun reverseList(head: ListNode?): ListNode? { + // temp用来存储临时的节点 + var temp: ListNode? + // cur用来遍历链表 + var cur: ListNode? = head + // pre用来作为链表反转的工具 + // pre是比pre前一位的节点 + var pre: ListNode? = null + while (cur != null) { + // 临时存储原本cur的下一个节点 + temp = cur.next + // 使cur下一节点地址为它之前的 + cur.next = pre + // 之后随着cur的遍历移动pre + pre = cur; + // 移动cur遍历链表各个节点 + cur = temp; + } + // 由于开头使用pre为null,所以cur等于链表本身长度+1, + // 此时pre在cur前一位,所以此时pre为头节点 + return pre; + } +} +``` + +### Swift: + +```swift +/// 双指针法 (迭代) +/// - Parameter head: 头结点 +/// - Returns: 翻转后的链表头结点 +func reverseList(_ head: ListNode?) -> ListNode? { + if head == nil || head?.next == nil { + return head + } + var pre: ListNode? = nil + var cur: ListNode? = head + var temp: ListNode? = nil + while cur != nil { + temp = cur?.next + cur?.next = pre + pre = cur + cur = temp + } + return pre +} + +/// 递归 +/// - Parameter head: 头结点 +/// - Returns: 翻转后的链表头结点 +func reverseList2(_ head: ListNode?) -> ListNode? { + return reverse(pre: nil, cur: head) +} +func reverse(pre: ListNode?, cur: ListNode?) -> ListNode? { + if cur == nil { + return pre + } + let temp: ListNode? = cur?.next + cur?.next = pre + return reverse(pre: cur, cur: temp) +} +``` + +### C: +双指针法: + +```c +struct ListNode* reverseList(struct ListNode* head){ + //保存cur的下一个结点 + struct ListNode* temp; + //pre指针指向前一个当前结点的前一个结点 + struct ListNode* pre = NULL; + //用head代替cur,也可以再定义一个cur结点指向head。 + while(head) { + //保存下一个结点的位置 + temp = head->next; + //翻转操作 + head->next = pre; + //更新结点 + pre = head; + head = temp; + } + return pre; +} +``` + +递归法: +```c +struct ListNode* reverse(struct ListNode* pre, struct ListNode* cur) { + if(!cur) + return pre; + struct ListNode* temp = cur->next; + cur->next = pre; + //将cur作为pre传入下一层 + //将temp作为cur传入下一层,改变其指针指向当前cur + return reverse(cur, temp); +} + +struct ListNode* reverseList(struct ListNode* head){ + return reverse(NULL, head); +} +``` + + + +### PHP: + +```php +// 双指针法: +function reverseList($head) { + $cur = $head; + $pre = NULL; + while($cur){ + $temp = $cur->next; + $cur->next = $pre; + $pre = $cur; + $cur = $temp; + } + return $pre; + } +``` + +### Scala: +双指针法: + +```scala +object Solution { + def reverseList(head: ListNode): ListNode = { + var pre: ListNode = null + var cur = head + while (cur != null) { + var tmp = cur.next + cur.next = pre + pre = cur + cur = tmp + } + pre + } +} +``` +递归法: +```scala +object Solution { + def reverseList(head: ListNode): ListNode = { + reverse(null, head) + } + + def reverse(pre: ListNode, cur: ListNode): ListNode = { + if (cur == null) { + return pre // 如果当前cur为空,则返回pre + } + val tmp: ListNode = cur.next + cur.next = pre + reverse(cur, tmp) // 此时cur成为前一个节点,tmp是当前节点 + } + +} +``` + +### Rust: +双指针法: + +```rust +impl Solution { + pub fn reverse_list(head: Option>) -> Option> { + let mut cur = head; + let mut pre = None; + while let Some(mut node) = cur.take() { + cur = node.next; + node.next = pre; + pre = Some(node); + } + pre + } +} +``` + +递归法: + +```rust +impl Solution { + pub fn reverse_list(head: Option>) -> Option> { + fn rev( + mut head: Option>, + mut pre: Option>, + ) -> Option> { + if let Some(mut node) = head.take() { + let cur = node.next; + node.next = pre; + pre = Some(node); + return rev(cur, pre); + } + pre + } + rev(head, None) + } +} +``` +### C#: +三指针法, 感觉会更直观: + +```cs +public LinkNumbers Reverse() +{ + ///用三指针,写的过程中能够弥补二指针在翻转过程中的想象 + LinkNumbers pre = null; + var move = root; + var next = root; + + while (next != null) + { + next = next.linknext; + move.linknext = pre; + pre = move; + move = next; + } + root = pre; + return root; +} + +///LinkNumbers的定义 +public class LinkNumbers +{ + /// + /// 链表值 + /// + public int value { get; set; } + + /// + /// 链表指针 + /// + public LinkNumbers linknext { get; set; } +} +``` + +## 其他解法 + +### 使用虚拟头结点解决链表反转 + +> 使用虚拟头结点,通过头插法实现链表的反转(不需要栈) + +```java +// 迭代方法:增加虚头结点,使用头插法实现链表翻转 +public static ListNode reverseList1(ListNode head) { + // 创建虚头结点 + ListNode dumpyHead = new ListNode(-1); + dumpyHead.next = null; + // 遍历所有节点 + ListNode cur = head; + while(cur != null){ + ListNode temp = cur.next; + // 头插法 + cur.next = dumpyHead.next; + dumpyHead.next = cur; + cur = temp; + } + return dumpyHead.next; +} +``` + + + +### 使用栈解决反转链表的问题 + +* 首先将所有的结点入栈 +* 然后创建一个虚拟虚拟头结点,让cur指向虚拟头结点。然后开始循环出栈,每出来一个元素,就把它加入到以虚拟头结点为头结点的链表当中,最后返回即可。 + +```java +public ListNode reverseList(ListNode head) { + // 如果链表为空,则返回空 + if (head == null) return null; + // 如果链表中只有只有一个元素,则直接返回 + if (head.next == null) return head; + // 创建栈 每一个结点都入栈 + Stack stack = new Stack<>(); + ListNode cur = head; + while (cur != null) { + stack.push(cur); + cur = cur.next; + } + // 创建一个虚拟头结点 + ListNode pHead = new ListNode(0); + cur = pHead; + while (!stack.isEmpty()) { + ListNode node = stack.pop(); + cur.next = node; + cur = cur.next; + } + // 最后一个元素的next要赋值为空 + cur.next = null; + return pHead.next; +} +``` + +> 采用这种方法需要注意一点。就是当整个出栈循环结束以后,cur正好指向原来链表的第一个结点,而此时结点1中的next指向的是结点2,因此最后还需要`cur.next = null` +![image-20230117195418626](https://raw.githubusercontent.com/liyuxuan7762/MyImageOSS/master/md_images/image-20230117195418626.png) + +

+ + + diff --git a/problems/0206.翻转链表.md b/problems/0206.翻转链表.md index c63c998d..5a57939a 100644 --- a/problems/0206.翻转链表.md +++ b/problems/0206.翻转链表.md @@ -17,14 +17,12 @@ 输入: 1->2->3->4->5->NULL 输出: 5->4->3->2->1->NULL -# 算法公开课 +## 算法公开课 **[《代码随想录》算法视频公开课](https://programmercarl.com/other/gongkaike.html):[帮你拿下反转链表 | LeetCode:206.反转链表](https://www.bilibili.com/video/BV1nB4y1i7eL),相信结合视频再看本篇题解,更有助于大家对本题的理解**。 -# 思路 - -本题我录制了B站视频,[帮你拿下反转链表 | LeetCode:206.反转链表](https://www.bilibili.com/video/BV1nB4y1i7eL),相信结合视频在看本篇题解,更有助于大家对链表的理解。 +## 思路 如果再定义一个新的链表,实现链表元素的反转,其实这是对内存空间的浪费。 @@ -51,9 +49,7 @@ 最后,cur 指针已经指向了null,循环结束,链表也反转完毕了。 此时我们return pre指针就可以了,pre指针就指向了新的头结点。 -# C++代码 - -## 双指针法 +### 双指针法 ```CPP class Solution { public: @@ -76,7 +72,7 @@ public: * 时间复杂度: O(n) * 空间复杂度: O(1) -## 递归法 +### 递归法 递归法相对抽象一些,但是其实和双指针法是一样的逻辑,同样是当cur为空的时候循环结束,不断将cur指向pre的过程。 @@ -137,8 +133,8 @@ public: ## 其他语言版本 +### Java: -Java: ```java // 双指针 class Solution { @@ -198,7 +194,8 @@ class Solution { } ``` -Python +### Python: + ```python (版本一)双指针法 # Definition for singly-linked list. @@ -219,8 +216,6 @@ class Solution: return pre ``` -Python递归法: - ```python (版本二)递归法 # Definition for singly-linked list. @@ -242,7 +237,7 @@ class Solution: -Go: +### Go: ```go //双指针 @@ -273,7 +268,7 @@ func help(pre, head *ListNode)*ListNode{ } ``` -javaScript: +### JavaScript: ```js /** @@ -328,7 +323,7 @@ var reverseList = function(head) { }; ``` -TypeScript: +### TypeScript: ```typescript // 双指针法 @@ -376,7 +371,7 @@ function reverseList(head: ListNode | null): ListNode | null { }; ``` -Ruby: +### Ruby: ```ruby # 双指针 @@ -421,7 +416,8 @@ def reverse(pre, cur) end ``` -Kotlin: +### Kotlin: + ```Kotlin fun reverseList(head: ListNode?): ListNode? { var pre: ListNode? = null @@ -471,7 +467,8 @@ class Solution { } ``` -Swift: +### Swift: + ```swift /// 双指针法 (迭代) /// - Parameter head: 头结点 @@ -508,8 +505,9 @@ func reverse(pre: ListNode?, cur: ListNode?) -> ListNode? { } ``` -C: +### C: 双指针法: + ```c struct ListNode* reverseList(struct ListNode* head){ //保存cur的下一个结点 @@ -549,7 +547,8 @@ struct ListNode* reverseList(struct ListNode* head){ -PHP: +### PHP: + ```php // 双指针法: function reverseList($head) { @@ -565,8 +564,9 @@ function reverseList($head) { } ``` -Scala: +### Scala: 双指针法: + ```scala object Solution { def reverseList(head: ListNode): ListNode = { @@ -601,7 +601,7 @@ object Solution { } ``` -Rust: +### Rust: 双指针法: ```rust @@ -640,7 +640,7 @@ impl Solution { } } ``` -C#: +### C#: 三指针法, 感觉会更直观: ```cs @@ -677,11 +677,11 @@ public class LinkNumbers } ``` +## 其他解法 +### 使用虚拟头结点解决链表反转 -## 使用虚拟头结点解决链表翻转 - -> 使用虚拟头结点,通过头插法实现链表的翻转(不需要栈) +> 使用虚拟头结点,通过头插法实现链表的反转(不需要栈) ```java // 迭代方法:增加虚头结点,使用头插法实现链表翻转 @@ -704,7 +704,7 @@ public static ListNode reverseList1(ListNode head) { -## 使用栈解决反转链表的问题 +### 使用栈解决反转链表的问题 * 首先将所有的结点入栈 * 然后创建一个虚拟虚拟头结点,让cur指向虚拟头结点。然后开始循环出栈,每出来一个元素,就把它加入到以虚拟头结点为头结点的链表当中,最后返回即可。 @@ -743,4 +743,3 @@ public ListNode reverseList(ListNode head) { - From 2acceb7474b60ad4aa16eef4b9bf94657ac85aeb Mon Sep 17 00:00:00 2001 From: jinbudaily <18336218010@163.com> Date: Tue, 18 Jul 2023 15:00:29 +0800 Subject: [PATCH 038/122] =?UTF-8?q?=E6=9B=B4=E6=96=B0=20024.=E4=B8=A4?= =?UTF-8?q?=E4=B8=A4=E4=BA=A4=E6=8D=A2=E9=93=BE=E8=A1=A8=E4=B8=AD=E7=9A=84?= =?UTF-8?q?=E8=8A=82=E7=82=B9=20=E6=8E=92=E7=89=88=E6=A0=BC=E5=BC=8F?= =?UTF-8?q?=E4=BF=AE=E5=A4=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- problems/0024.两两交换链表中的节点.md | 37 +- problems/0206.反转链表.md | 745 -------------------------- 2 files changed, 23 insertions(+), 759 deletions(-) delete mode 100644 problems/0206.反转链表.md diff --git a/problems/0024.两两交换链表中的节点.md b/problems/0024.两两交换链表中的节点.md index d7c03b64..c612c4b3 100644 --- a/problems/0024.两两交换链表中的节点.md +++ b/problems/0024.两两交换链表中的节点.md @@ -5,7 +5,7 @@

参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!

-## 24. 两两交换链表中的节点 +# 24. 两两交换链表中的节点 [力扣题目链接](https://leetcode.cn/problems/swap-nodes-in-pairs/) @@ -16,9 +16,11 @@ 24.两两交换链表中的节点-题意 -## 思路 +## 算法公开课 -《代码随想录》算法公开课:[帮你把链表细节学清楚! | LeetCode:24. 两两交换链表中的节点](https://www.bilibili.com/video/BV1YT411g7br),相信结合视频在看本篇题解,更有助于大家对链表的理解。 +**[《代码随想录》算法视频公开课](https://programmercarl.com/other/gongkaike.html):[帮你把链表细节学清楚! | LeetCode:24. 两两交换链表中的节点](https://www.bilibili.com/video/BV1YT411g7br),相信结合视频再看本篇题解,更有助于大家对本题的理解**。 + +## 思路 这道题目正常模拟就可以了。 @@ -88,7 +90,8 @@ public: ## 其他语言版本 -C: +### C: + ```c /** * Definition for singly-linked list. @@ -132,7 +135,7 @@ struct ListNode* swapPairs(struct ListNode* head){ } ``` -Java: +### Java: ```Java // 递归版本 @@ -176,7 +179,8 @@ class Solution { } ``` -Python: +### Python: + ```python # 递归版本 # Definition for singly-linked list. @@ -226,7 +230,8 @@ class Solution: ``` -Go: +### Go: + ```go func swapPairs(head *ListNode) *ListNode { dummy := &ListNode{ @@ -262,7 +267,8 @@ func swapPairs(head *ListNode) *ListNode { } ``` -Javascript: +### Javascript: + ```javascript var swapPairs = function (head) { let ret = new ListNode(0, head), temp = ret; @@ -277,7 +283,7 @@ var swapPairs = function (head) { }; ``` -TypeScript: +### TypeScript: ```typescript function swapPairs(head: ListNode | null): ListNode | null { @@ -296,7 +302,7 @@ function swapPairs(head: ListNode | null): ListNode | null { }; ``` -Kotlin: +### Kotlin: ```kotlin fun swapPairs(head: ListNode?): ListNode? { @@ -316,7 +322,8 @@ fun swapPairs(head: ListNode?): ListNode? { } ``` -Swift: +### Swift: + ```swift func swapPairs(_ head: ListNode?) -> ListNode? { if head == nil || head?.next == nil { @@ -337,7 +344,8 @@ func swapPairs(_ head: ListNode?) -> ListNode? { return dummyHead.next } ``` -Scala: +### Scala: + ```scala // 虚拟头节点 object Solution { @@ -361,7 +369,8 @@ object Solution { } ``` -PHP: +### PHP: + ```php //虚拟头结点 function swapPairs($head) { @@ -404,7 +413,7 @@ function swapPairs($head) } ``` -Rust: +### Rust: ```rust // 虚拟头节点 diff --git a/problems/0206.反转链表.md b/problems/0206.反转链表.md deleted file mode 100644 index 5a57939a..00000000 --- a/problems/0206.反转链表.md +++ /dev/null @@ -1,745 +0,0 @@ -

- - - -

参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!

- - -> 反转链表的写法很简单,一些同学甚至可以背下来但过一阵就忘了该咋写,主要是因为没有理解真正的反转过程。 - -# 206.反转链表 - -[力扣题目链接](https://leetcode.cn/problems/reverse-linked-list/) - -题意:反转一个单链表。 - -示例: -输入: 1->2->3->4->5->NULL -输出: 5->4->3->2->1->NULL - -## 算法公开课 - -**[《代码随想录》算法视频公开课](https://programmercarl.com/other/gongkaike.html):[帮你拿下反转链表 | LeetCode:206.反转链表](https://www.bilibili.com/video/BV1nB4y1i7eL),相信结合视频再看本篇题解,更有助于大家对本题的理解**。 - - -## 思路 - -如果再定义一个新的链表,实现链表元素的反转,其实这是对内存空间的浪费。 - -其实只需要改变链表的next指针的指向,直接将链表反转 ,而不用重新定义一个新的链表,如图所示: - - -![206_反转链表](https://code-thinking-1253855093.file.myqcloud.com/pics/20210218090901207.png) - -之前链表的头节点是元素1, 反转之后头结点就是元素5 ,这里并没有添加或者删除节点,仅仅是改变next指针的方向。 - -那么接下来看一看是如何反转的呢? - -我们拿有示例中的链表来举例,如动画所示:(纠正:动画应该是先移动pre,在移动cur) - -![](https://code-thinking.cdn.bcebos.com/gifs/206.%E7%BF%BB%E8%BD%AC%E9%93%BE%E8%A1%A8.gif) - -首先定义一个cur指针,指向头结点,再定义一个pre指针,初始化为null。 - -然后就要开始反转了,首先要把 cur->next 节点用tmp指针保存一下,也就是保存一下这个节点。 - -为什么要保存一下这个节点呢,因为接下来要改变 cur->next 的指向了,将cur->next 指向pre ,此时已经反转了第一个节点了。 - -接下来,就是循环走如下代码逻辑了,继续移动pre和cur指针。 - -最后,cur 指针已经指向了null,循环结束,链表也反转完毕了。 此时我们return pre指针就可以了,pre指针就指向了新的头结点。 - -### 双指针法 -```CPP -class Solution { -public: - ListNode* reverseList(ListNode* head) { - ListNode* temp; // 保存cur的下一个节点 - ListNode* cur = head; - ListNode* pre = NULL; - while(cur) { - temp = cur->next; // 保存一下 cur的下一个节点,因为接下来要改变cur->next - cur->next = pre; // 翻转操作 - // 更新pre 和 cur指针 - pre = cur; - cur = temp; - } - return pre; - } -}; -``` - -* 时间复杂度: O(n) -* 空间复杂度: O(1) - -### 递归法 - -递归法相对抽象一些,但是其实和双指针法是一样的逻辑,同样是当cur为空的时候循环结束,不断将cur指向pre的过程。 - -关键是初始化的地方,可能有的同学会不理解, 可以看到双指针法中初始化 cur = head,pre = NULL,在递归法中可以从如下代码看出初始化的逻辑也是一样的,只不过写法变了。 - -具体可以看代码(已经详细注释),**双指针法写出来之后,理解如下递归写法就不难了,代码逻辑都是一样的。** -```CPP -class Solution { -public: - ListNode* reverse(ListNode* pre,ListNode* cur){ - if(cur == NULL) return pre; - ListNode* temp = cur->next; - cur->next = pre; - // 可以和双指针法的代码进行对比,如下递归的写法,其实就是做了这两步 - // pre = cur; - // cur = temp; - return reverse(cur,temp); - } - ListNode* reverseList(ListNode* head) { - // 和双指针法初始化是一样的逻辑 - // ListNode* cur = head; - // ListNode* pre = NULL; - return reverse(NULL, head); - } - -}; -``` - -* 时间复杂度: O(n), 要递归处理链表的每个节点 -* 空间复杂度: O(n), 递归调用了 n 层栈空间 - -我们可以发现,上面的递归写法和双指针法实质上都是从前往后翻转指针指向,其实还有另外一种与双指针法不同思路的递归写法:从后往前翻转指针指向。 - -具体代码如下(带详细注释): - -```CPP -class Solution { -public: - ListNode* reverseList(ListNode* head) { - // 边缘条件判断 - if(head == NULL) return NULL; - if (head->next == NULL) return head; - - // 递归调用,翻转第二个节点开始往后的链表 - ListNode *last = reverseList(head->next); - // 翻转头节点与第二个节点的指向 - head->next->next = head; - // 此时的 head 节点为尾节点,next 需要指向 NULL - head->next = NULL; - return last; - } -}; -``` - -* 时间复杂度: O(n) -* 空间复杂度: O(n) - - -## 其他语言版本 - -### Java: - -```java -// 双指针 -class Solution { - public ListNode reverseList(ListNode head) { - ListNode prev = null; - ListNode cur = head; - ListNode temp = null; - while (cur != null) { - temp = cur.next;// 保存下一个节点 - cur.next = prev; - prev = cur; - cur = temp; - } - return prev; - } -} -``` - -```java -// 递归 -class Solution { - public ListNode reverseList(ListNode head) { - return reverse(null, head); - } - - private ListNode reverse(ListNode prev, ListNode cur) { - if (cur == null) { - return prev; - } - ListNode temp = null; - temp = cur.next;// 先保存下一个节点 - cur.next = prev;// 反转 - // 更新prev、cur位置 - // prev = cur; - // cur = temp; - return reverse(cur, temp); - } -} -``` - -```java -// 从后向前递归 -class Solution { - ListNode reverseList(ListNode head) { - // 边缘条件判断 - if(head == null) return null; - if (head.next == null) return head; - - // 递归调用,翻转第二个节点开始往后的链表 - ListNode last = reverseList(head.next); - // 翻转头节点与第二个节点的指向 - head.next.next = head; - // 此时的 head 节点为尾节点,next 需要指向 NULL - head.next = null; - return last; - } -} -``` - -### Python: - -```python -(版本一)双指针法 -# Definition for singly-linked list. -# class ListNode: -# def __init__(self, val=0, next=None): -# self.val = val -# self.next = next -class Solution: - def reverseList(self, head: ListNode) -> ListNode: - cur = head - pre = None - while cur: - temp = cur.next # 保存一下 cur的下一个节点,因为接下来要改变cur->next - cur.next = pre #反转 - #更新pre、cur指针 - pre = cur - cur = temp - return pre -``` - -```python -(版本二)递归法 -# Definition for singly-linked list. -# class ListNode: -# def __init__(self, val=0, next=None): -# self.val = val -# self.next = next -class Solution: - def reverseList(self, head: ListNode) -> ListNode: - return self.reverse(head, None) - def reverse(self, cur: ListNode, pre: ListNode) -> ListNode: - if cur == None: - return pre - temp = cur.next - cur.next = pre - return self.reverse(temp, cur) - -``` - - - -### Go: - -```go -//双指针 -func reverseList(head *ListNode) *ListNode { - var pre *ListNode - cur := head - for cur != nil { - next := cur.Next - cur.Next = pre - pre = cur - cur = next - } - return pre -} - -//递归 -func reverseList(head *ListNode) *ListNode { - return help(nil, head) -} - -func help(pre, head *ListNode)*ListNode{ - if head == nil { - return pre - } - next := head.Next - head.Next = pre - return help(head, next) -} - -``` -### JavaScript: - -```js -/** - * @param {ListNode} head - * @return {ListNode} - */ - -// 双指针: -var reverseList = function(head) { - if(!head || !head.next) return head; - let temp = null, pre = null, cur = head; - while(cur) { - temp = cur.next; - cur.next = pre; - pre = cur; - cur = temp; - } - // temp = cur = null; - return pre; -}; - -// 递归: -var reverse = function(pre, head) { - if(!head) return pre; - const temp = head.next; - head.next = pre; - pre = head - return reverse(pre, temp); -} - -var reverseList = function(head) { - return reverse(null, head); -}; - -// 递归2 -var reverse = function(head) { - if(!head || !head.next) return head; - // 从后往前翻 - const pre = reverse(head.next); - head.next = pre.next; - pre.next = head; - return head; -} - -var reverseList = function(head) { - let cur = head; - while(cur && cur.next) { - cur = cur.next; - } - reverse(head); - return cur; -}; -``` - -### TypeScript: - -```typescript -// 双指针法 -function reverseList(head: ListNode | null): ListNode | null { - let preNode: ListNode | null = null, - curNode: ListNode | null = head, - tempNode: ListNode | null; - while (curNode) { - tempNode = curNode.next; - curNode.next = preNode; - preNode = curNode; - curNode = tempNode; - } - return preNode; -}; - -// 递归(从前往后翻转) -function reverseList(head: ListNode | null): ListNode | null { - function recur(preNode: ListNode | null, curNode: ListNode | null): ListNode | null { - if (curNode === null) return preNode; - let tempNode: ListNode | null = curNode.next; - curNode.next = preNode; - preNode = curNode; - curNode = tempNode; - return recur(preNode, curNode); - } - return recur(null, head); -}; - -// 递归(从后往前翻转) -function reverseList(head: ListNode | null): ListNode | null { - if (head === null) return null; - let newHead: ListNode | null; - function recur(node: ListNode | null, preNode: ListNode | null): void { - if (node.next === null) { - newHead = node; - newHead.next = preNode; - } else { - recur(node.next, node); - node.next = preNode; - } - } - recur(head, null); - return newHead; -}; -``` - -### Ruby: - -```ruby -# 双指针 -# Definition for singly-linked list. -# class ListNode -# attr_accessor :val, :next -# def initialize(val = 0, _next = nil) -# @val = val -# @next = _next -# end -# end -def reverse_list(head) - # return nil if head.nil? # 循环判断条件亦能起到相同作用因此不必单独判断 - cur, per = head, nil - until cur.nil? - tem = cur.next - cur.next = per - per = cur - cur = tem - end - per -end - -# 递归 -# Definition for singly-linked list. -# class ListNode -# attr_accessor :val, :next -# def initialize(val = 0, _next = nil) -# @val = val -# @next = _next -# end -# end -def reverse_list(head) - reverse(nil, head) -end - -def reverse(pre, cur) - return pre if cur.nil? - tem = cur.next - cur.next = pre - reverse(cur, tem) # 通过递归实现双指针法中的更新操作 -end -``` - -### Kotlin: - -```Kotlin -fun reverseList(head: ListNode?): ListNode? { - var pre: ListNode? = null - var cur = head - while (cur != null) { - val temp = cur.next - cur.next = pre - pre = cur - cur = temp - } - return pre -} -``` -```kotlin -/** - * Example: - * var li = ListNode(5) - * var v = li.`val` - * Definition for singly-linked list. - * class ListNode(var `val`: Int) { - * var next: ListNode? = null - * } - */ -class Solution { - fun reverseList(head: ListNode?): ListNode? { - // temp用来存储临时的节点 - var temp: ListNode? - // cur用来遍历链表 - var cur: ListNode? = head - // pre用来作为链表反转的工具 - // pre是比pre前一位的节点 - var pre: ListNode? = null - while (cur != null) { - // 临时存储原本cur的下一个节点 - temp = cur.next - // 使cur下一节点地址为它之前的 - cur.next = pre - // 之后随着cur的遍历移动pre - pre = cur; - // 移动cur遍历链表各个节点 - cur = temp; - } - // 由于开头使用pre为null,所以cur等于链表本身长度+1, - // 此时pre在cur前一位,所以此时pre为头节点 - return pre; - } -} -``` - -### Swift: - -```swift -/// 双指针法 (迭代) -/// - Parameter head: 头结点 -/// - Returns: 翻转后的链表头结点 -func reverseList(_ head: ListNode?) -> ListNode? { - if head == nil || head?.next == nil { - return head - } - var pre: ListNode? = nil - var cur: ListNode? = head - var temp: ListNode? = nil - while cur != nil { - temp = cur?.next - cur?.next = pre - pre = cur - cur = temp - } - return pre -} - -/// 递归 -/// - Parameter head: 头结点 -/// - Returns: 翻转后的链表头结点 -func reverseList2(_ head: ListNode?) -> ListNode? { - return reverse(pre: nil, cur: head) -} -func reverse(pre: ListNode?, cur: ListNode?) -> ListNode? { - if cur == nil { - return pre - } - let temp: ListNode? = cur?.next - cur?.next = pre - return reverse(pre: cur, cur: temp) -} -``` - -### C: -双指针法: - -```c -struct ListNode* reverseList(struct ListNode* head){ - //保存cur的下一个结点 - struct ListNode* temp; - //pre指针指向前一个当前结点的前一个结点 - struct ListNode* pre = NULL; - //用head代替cur,也可以再定义一个cur结点指向head。 - while(head) { - //保存下一个结点的位置 - temp = head->next; - //翻转操作 - head->next = pre; - //更新结点 - pre = head; - head = temp; - } - return pre; -} -``` - -递归法: -```c -struct ListNode* reverse(struct ListNode* pre, struct ListNode* cur) { - if(!cur) - return pre; - struct ListNode* temp = cur->next; - cur->next = pre; - //将cur作为pre传入下一层 - //将temp作为cur传入下一层,改变其指针指向当前cur - return reverse(cur, temp); -} - -struct ListNode* reverseList(struct ListNode* head){ - return reverse(NULL, head); -} -``` - - - -### PHP: - -```php -// 双指针法: -function reverseList($head) { - $cur = $head; - $pre = NULL; - while($cur){ - $temp = $cur->next; - $cur->next = $pre; - $pre = $cur; - $cur = $temp; - } - return $pre; - } -``` - -### Scala: -双指针法: - -```scala -object Solution { - def reverseList(head: ListNode): ListNode = { - var pre: ListNode = null - var cur = head - while (cur != null) { - var tmp = cur.next - cur.next = pre - pre = cur - cur = tmp - } - pre - } -} -``` -递归法: -```scala -object Solution { - def reverseList(head: ListNode): ListNode = { - reverse(null, head) - } - - def reverse(pre: ListNode, cur: ListNode): ListNode = { - if (cur == null) { - return pre // 如果当前cur为空,则返回pre - } - val tmp: ListNode = cur.next - cur.next = pre - reverse(cur, tmp) // 此时cur成为前一个节点,tmp是当前节点 - } - -} -``` - -### Rust: -双指针法: - -```rust -impl Solution { - pub fn reverse_list(head: Option>) -> Option> { - let mut cur = head; - let mut pre = None; - while let Some(mut node) = cur.take() { - cur = node.next; - node.next = pre; - pre = Some(node); - } - pre - } -} -``` - -递归法: - -```rust -impl Solution { - pub fn reverse_list(head: Option>) -> Option> { - fn rev( - mut head: Option>, - mut pre: Option>, - ) -> Option> { - if let Some(mut node) = head.take() { - let cur = node.next; - node.next = pre; - pre = Some(node); - return rev(cur, pre); - } - pre - } - rev(head, None) - } -} -``` -### C#: -三指针法, 感觉会更直观: - -```cs -public LinkNumbers Reverse() -{ - ///用三指针,写的过程中能够弥补二指针在翻转过程中的想象 - LinkNumbers pre = null; - var move = root; - var next = root; - - while (next != null) - { - next = next.linknext; - move.linknext = pre; - pre = move; - move = next; - } - root = pre; - return root; -} - -///LinkNumbers的定义 -public class LinkNumbers -{ - /// - /// 链表值 - /// - public int value { get; set; } - - /// - /// 链表指针 - /// - public LinkNumbers linknext { get; set; } -} -``` - -## 其他解法 - -### 使用虚拟头结点解决链表反转 - -> 使用虚拟头结点,通过头插法实现链表的反转(不需要栈) - -```java -// 迭代方法:增加虚头结点,使用头插法实现链表翻转 -public static ListNode reverseList1(ListNode head) { - // 创建虚头结点 - ListNode dumpyHead = new ListNode(-1); - dumpyHead.next = null; - // 遍历所有节点 - ListNode cur = head; - while(cur != null){ - ListNode temp = cur.next; - // 头插法 - cur.next = dumpyHead.next; - dumpyHead.next = cur; - cur = temp; - } - return dumpyHead.next; -} -``` - - - -### 使用栈解决反转链表的问题 - -* 首先将所有的结点入栈 -* 然后创建一个虚拟虚拟头结点,让cur指向虚拟头结点。然后开始循环出栈,每出来一个元素,就把它加入到以虚拟头结点为头结点的链表当中,最后返回即可。 - -```java -public ListNode reverseList(ListNode head) { - // 如果链表为空,则返回空 - if (head == null) return null; - // 如果链表中只有只有一个元素,则直接返回 - if (head.next == null) return head; - // 创建栈 每一个结点都入栈 - Stack stack = new Stack<>(); - ListNode cur = head; - while (cur != null) { - stack.push(cur); - cur = cur.next; - } - // 创建一个虚拟头结点 - ListNode pHead = new ListNode(0); - cur = pHead; - while (!stack.isEmpty()) { - ListNode node = stack.pop(); - cur.next = node; - cur = cur.next; - } - // 最后一个元素的next要赋值为空 - cur.next = null; - return pHead.next; -} -``` - -> 采用这种方法需要注意一点。就是当整个出栈循环结束以后,cur正好指向原来链表的第一个结点,而此时结点1中的next指向的是结点2,因此最后还需要`cur.next = null` -![image-20230117195418626](https://raw.githubusercontent.com/liyuxuan7762/MyImageOSS/master/md_images/image-20230117195418626.png) - -

- - - From a64e11b09ad66f4a1ea22cdc3603e5cde85d88ef Mon Sep 17 00:00:00 2001 From: jinbudaily <18336218010@163.com> Date: Tue, 18 Jul 2023 15:13:42 +0800 Subject: [PATCH 039/122] =?UTF-8?q?=E6=9B=B4=E6=96=B0=20019.=E5=88=A0?= =?UTF-8?q?=E9=99=A4=E9=93=BE=E8=A1=A8=E7=9A=84=E5=80=92=E6=95=B0=E7=AC=AC?= =?UTF-8?q?n=E4=B8=AA=E8=8A=82=E7=82=B9=20=E6=8E=92=E7=89=88=E6=A0=BC?= =?UTF-8?q?=E5=BC=8F=E4=BF=AE=E5=A4=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- problems/0019.删除链表的倒数第N个节点.md | 39 +++++++++++++++--------- 1 file changed, 24 insertions(+), 15 deletions(-) diff --git a/problems/0019.删除链表的倒数第N个节点.md b/problems/0019.删除链表的倒数第N个节点.md index 84eac96b..1c95ad5b 100644 --- a/problems/0019.删除链表的倒数第N个节点.md +++ b/problems/0019.删除链表的倒数第N个节点.md @@ -7,7 +7,7 @@ -## 19.删除链表的倒数第N个节点 +# 19.删除链表的倒数第N个节点 [力扣题目链接](https://leetcode.cn/problems/remove-nth-node-from-end-of-list/) @@ -31,11 +31,13 @@ 输入:head = [1,2], n = 1 输出:[1] +## 算法公开课 + +**[《代码随想录》算法视频公开课](https://programmercarl.com/other/gongkaike.html)::[链表遍历学清楚! | LeetCode:19.删除链表倒数第N个节点](https://www.bilibili.com/video/BV1vW4y1U7Gf),相信结合视频再看本篇题解,更有助于大家对链表的理解。** + ## 思路 -《代码随想录》算法公开课:[链表遍历学清楚! | LeetCode:19.删除链表倒数第N个节点](https://www.bilibili.com/video/BV1vW4y1U7Gf),相信结合视频在看本篇题解,更有助于大家对链表的理解。 - 双指针的经典应用,如果要删除倒数第n个节点,让fast移动n步,然后让fast和slow同时移动,直到fast指向链表末尾。删掉slow所指向的节点就可以了。 @@ -93,7 +95,7 @@ public: ## 其他语言版本 -java: +### Java: ```java public ListNode removeNthFromEnd(ListNode head, int n){ @@ -120,7 +122,8 @@ public ListNode removeNthFromEnd(ListNode head, int n){ } ``` -Python: +### Python: + ```python # Definition for singly-linked list. # class ListNode: @@ -151,7 +154,8 @@ class Solution: return dummy_head.next ``` -Go: +### Go: + ```Go /** * Definition for singly-linked list. @@ -178,7 +182,7 @@ func removeNthFromEnd(head *ListNode, n int) *ListNode { } ``` -JavaScript: +### JavaScript: ```js /** @@ -198,7 +202,7 @@ var removeNthFromEnd = function(head, n) { return ret.next; }; ``` -TypeScript: +### TypeScript: 版本一(快慢指针法): @@ -263,7 +267,7 @@ function removeNthFromEnd(head: ListNode | null, n: number): ListNode | null { }; ``` -Kotlin: +### Kotlin: ```Kotlin fun removeNthFromEnd(head: ListNode?, n: Int): ListNode? { @@ -284,7 +288,8 @@ fun removeNthFromEnd(head: ListNode?, n: Int): ListNode? { } ``` -Swift: +### Swift: + ```swift func removeNthFromEnd(_ head: ListNode?, _ n: Int) -> ListNode? { if head == nil { @@ -309,8 +314,8 @@ func removeNthFromEnd(_ head: ListNode?, _ n: Int) -> ListNode? { } ``` +### PHP: -PHP: ```php function removeNthFromEnd($head, $n) { // 设置虚拟头节点 @@ -332,7 +337,8 @@ function removeNthFromEnd($head, $n) { } ``` -Scala: +### Scala: + ```scala object Solution { def removeNthFromEnd(head: ListNode, n: Int): ListNode = { @@ -356,7 +362,8 @@ object Solution { } ``` -Rust: +### Rust: + ```rust impl Solution { pub fn remove_nth_from_end(head: Option>, mut n: i32) -> Option> { @@ -377,7 +384,8 @@ impl Solution { } } ``` -C语言 +### C: + ```c /**c语言单链表的定义 * Definition for singly-linked list. @@ -412,7 +420,8 @@ struct ListNode* removeNthFromEnd(struct ListNode* head, int n) { ``` -C#: +### C#: + ```csharp public class Solution { public ListNode RemoveNthFromEnd(ListNode head, int n) { From 8eb214c06025e359d9c4a40d87d4e3075f5d8bdf Mon Sep 17 00:00:00 2001 From: jinbudaily <18336218010@163.com> Date: Tue, 18 Jul 2023 15:23:24 +0800 Subject: [PATCH 040/122] =?UTF-8?q?=E9=9D=A2=E8=AF=95=E9=A2=98=2002.07.?= =?UTF-8?q?=E9=93=BE=E8=A1=A8=E7=9B=B8=E4=BA=A4=20=E6=8E=92=E7=89=88?= =?UTF-8?q?=E6=A0=BC=E5=BC=8F=E4=BF=AE=E5=A4=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- problems/面试题02.07.链表相交.md | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/problems/面试题02.07.链表相交.md b/problems/面试题02.07.链表相交.md index 75e03116..833eadca 100644 --- a/problems/面试题02.07.链表相交.md +++ b/problems/面试题02.07.链表相交.md @@ -34,6 +34,7 @@ ![](https://code-thinking-1253855093.file.myqcloud.com/pics/20211219221812.png)![](https://code-thinking-1253855093.file.myqcloud.com/pics/20211219221812.png) + ## 思路 @@ -101,7 +102,7 @@ public: ## 其他语言版本 -Java: +### Java: ```Java public class Solution { @@ -150,8 +151,7 @@ public class Solution { } ``` - -Python: +### Python: ```python @@ -280,7 +280,7 @@ class Solution: return pointerA ``` -Go: +### Go: ```go func getIntersectionNode(headA, headB *ListNode) *ListNode { @@ -341,7 +341,7 @@ func getIntersectionNode(headA, headB *ListNode) *ListNode { } ``` -JavaScript: +### JavaScript: ```js var getListLen = function(head) { @@ -376,7 +376,7 @@ var getIntersectionNode = function(headA, headB) { }; ``` -TypeScript: +### TypeScript: ```typescript function getIntersectionNode(headA: ListNode | null, headB: ListNode | null): ListNode | null { @@ -413,7 +413,7 @@ function getIntersectionNode(headA: ListNode | null, headB: ListNode | null): Li }; ``` -C: +### C: ```c ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) { @@ -452,7 +452,7 @@ ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) { } ``` -Scala: +### Scala: ```scala object Solution { @@ -508,3 +508,4 @@ object Solution { + From 17d56ed722d41a8d463de2de71c72345a88a2df5 Mon Sep 17 00:00:00 2001 From: jinbudaily <18336218010@163.com> Date: Tue, 18 Jul 2023 15:30:49 +0800 Subject: [PATCH 041/122] =?UTF-8?q?=E6=9B=B4=E6=96=B0=200142.=E7=8E=AF?= =?UTF-8?q?=E5=BD=A2=E9=93=BE=E8=A1=A8II=20=E6=8E=92=E7=89=88=E6=A0=BC?= =?UTF-8?q?=E5=BC=8F=E4=BF=AE=E5=A4=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- problems/0141.环形链表.md | 11 ++++++----- problems/0142.环形链表II.md | 30 +++++++++++++++--------------- 2 files changed, 21 insertions(+), 20 deletions(-) diff --git a/problems/0141.环形链表.md b/problems/0141.环形链表.md index 7d7121a0..b1f42ba9 100644 --- a/problems/0141.环形链表.md +++ b/problems/0141.环形链表.md @@ -70,7 +70,7 @@ public: ## 其他语言版本 -### Java +### Java: ```java public class Solution { @@ -90,7 +90,7 @@ public class Solution { } ``` -### Python +### Python: ```python class Solution: @@ -105,7 +105,7 @@ class Solution: return False ``` -### Go +### Go: ```go func hasCycle(head *ListNode) bool { @@ -125,7 +125,7 @@ func hasCycle(head *ListNode) bool { } ``` -### JavaScript +### JavaScript: ```js var hasCycle = function(head) { @@ -141,7 +141,7 @@ var hasCycle = function(head) { }; ``` -### TypeScript +### TypeScript: ```typescript function hasCycle(head: ListNode | null): boolean { @@ -163,3 +163,4 @@ function hasCycle(head: ListNode | null): boolean { + diff --git a/problems/0142.环形链表II.md b/problems/0142.环形链表II.md index f87d2cd9..d20101a7 100644 --- a/problems/0142.环形链表II.md +++ b/problems/0142.环形链表II.md @@ -11,7 +11,7 @@ > 找到有没有环已经很不容易了,还要让我找到环的入口? -## 142.环形链表II +# 142.环形链表II [力扣题目链接](https://leetcode.cn/problems/linked-list-cycle-ii/) @@ -24,9 +24,11 @@ ![循环链表](https://code-thinking-1253855093.file.myqcloud.com/pics/20200816110112704.png) -## 思路 +## 算法公开课 -《代码随想录》算法公开课:[把环形链表讲清楚!| LeetCode:142.环形链表II](https://www.bilibili.com/video/BV1if4y1d7ob),相信结合视频在看本篇题解,更有助于大家对链表的理解。 +**[《代码随想录》算法视频公开课](https://programmercarl.com/other/gongkaike.html):[把环形链表讲清楚!| LeetCode:142.环形链表II](https://www.bilibili.com/video/BV1if4y1d7ob),相信结合视频在看本篇题解,更有助于大家对链表的理解。** + +## 思路 这道题目,不仅考察对链表的操作,而且还需要一些数学运算。 @@ -148,7 +150,7 @@ public: * 时间复杂度: O(n),快慢指针相遇前,指针走的次数小于链表长度,快慢指针相遇后,两个index指针走的次数也小于链表长度,总体为走的次数小于 2n * 空间复杂度: O(1) -## 补充 +### 补充 在推理过程中,大家可能有一个疑问就是:**为什么第一次在环中相遇,slow的 步数 是 x+y 而不是 x + 若干环的长度 + y 呢?** @@ -190,8 +192,7 @@ public: ## 其他语言版本 - -Java: +### Java: ```java public class Solution { @@ -217,8 +218,7 @@ public class Solution { } ``` - -Python: +### Python: ```python (版本一)快慢指针法 @@ -270,7 +270,7 @@ class Solution: return None ``` -Go: +### Go: ```go func detectCycle(head *ListNode) *ListNode { @@ -290,7 +290,7 @@ func detectCycle(head *ListNode) *ListNode { } ``` -javaScript +### JavaScript ```js // 两种循环实现方式 @@ -334,7 +334,7 @@ var detectCycle = function(head) { }; ``` -TypeScript: +### TypeScript: ```typescript function detectCycle(head: ListNode | null): ListNode | null { @@ -356,7 +356,7 @@ function detectCycle(head: ListNode | null): ListNode | null { }; ``` -Swift: +### Swift: ```swift class Solution { @@ -391,7 +391,7 @@ extension ListNode: Equatable { } ``` -C: +### C: ```c ListNode *detectCycle(ListNode *head) { @@ -410,7 +410,7 @@ ListNode *detectCycle(ListNode *head) { } ``` -Scala: +### Scala: ```scala object Solution { @@ -437,7 +437,7 @@ object Solution { } ``` -C#: +### C#: ```CSharp public class Solution { From 28b58782375755eda70381aaab630e52b50992c8 Mon Sep 17 00:00:00 2001 From: jinbudaily <18336218010@163.com> Date: Tue, 18 Jul 2023 15:33:00 +0800 Subject: [PATCH 042/122] =?UTF-8?q?=E6=9B=B4=E6=96=B0=20=E9=93=BE=E8=A1=A8?= =?UTF-8?q?=E6=80=BB=E7=BB=93=E7=AF=87=20=E6=8E=92=E7=89=88=E6=A0=BC?= =?UTF-8?q?=E5=BC=8F=E4=BF=AE=E5=A4=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- problems/链表总结篇.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/problems/链表总结篇.md b/problems/链表总结篇.md index cfbafc45..dacd4dee 100644 --- a/problems/链表总结篇.md +++ b/problems/链表总结篇.md @@ -3,7 +3,7 @@

参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!

- +# 链表总结篇 ## 链表的理论基础 @@ -68,7 +68,7 @@ [链表:链表相交](https://programmercarl.com/面试题02.07.链表相交.html)使用双指针来找到两个链表的交点(引用完全相同,即:内存地址完全相同的交点) -## 环形链表 +### 环形链表 在[链表:环找到了,那入口呢?](https://programmercarl.com/0142.环形链表II.html)中,讲解了在链表如何找环,以及如何找环的入口位置。 @@ -100,3 +100,4 @@ + From 607e4ebd49c67b6ddd4fcdd91b248e74ed0ed75e Mon Sep 17 00:00:00 2001 From: jinbudaily <18336218010@163.com> Date: Wed, 19 Jul 2023 14:18:19 +0800 Subject: [PATCH 043/122] =?UTF-8?q?=E6=9B=B4=E6=96=B0=20=E5=93=88=E5=B8=8C?= =?UTF-8?q?=E8=A1=A8=E7=90=86=E8=AE=BA=E5=9F=BA=E7=A1=80=20=E6=8E=92?= =?UTF-8?q?=E7=89=88=E6=A0=BC=E5=BC=8F=E4=BF=AE=E5=A4=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- problems/哈希表理论基础.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/problems/哈希表理论基础.md b/problems/哈希表理论基础.md index 0ab17ec0..3055875a 100644 --- a/problems/哈希表理论基础.md +++ b/problems/哈希表理论基础.md @@ -8,6 +8,8 @@ +# 哈希表理论基础 + ## 哈希表 首先什么是 哈希表,哈希表(英文名字为Hash table,国内也有一些算法书籍翻译为散列表,大家看到这两个名称知道都是指hash table就可以了)。 From c628aa65d438aaf4933f2b029ae71c93e3cfce63 Mon Sep 17 00:00:00 2001 From: jinbudaily <18336218010@163.com> Date: Wed, 19 Jul 2023 14:25:34 +0800 Subject: [PATCH 044/122] =?UTF-8?q?=E6=9B=B4=E6=96=B0=200242.=E6=9C=89?= =?UTF-8?q?=E6=95=88=E7=9A=84=E5=AD=97=E6=AF=8D=E5=BC=82=E4=BD=8D=E8=AF=8D?= =?UTF-8?q?=20=E6=8E=92=E7=89=88=E6=A0=BC=E5=BC=8F=E4=BF=AE=E5=A4=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- problems/0242.有效的字母异位词.md | 38 ++++++++++++++++--------------- 1 file changed, 20 insertions(+), 18 deletions(-) diff --git a/problems/0242.有效的字母异位词.md b/problems/0242.有效的字母异位词.md index 4ea43947..f47d8b05 100644 --- a/problems/0242.有效的字母异位词.md +++ b/problems/0242.有效的字母异位词.md @@ -7,7 +7,7 @@ > 数组就是简单的哈希表,但是数组的大小可不是无限开辟的 -## 242.有效的字母异位词 +# 242.有效的字母异位词 [力扣题目链接](https://leetcode.cn/problems/valid-anagram/) @@ -21,13 +21,14 @@ 输入: s = "rat", t = "car" 输出: false - **说明:** 你可以假设字符串只包含小写字母。 -## 思路 +## 算法公开课 -本题B站视频讲解版:[学透哈希表,数组使用有技巧!Leetcode:242.有效的字母异位词](https://www.bilibili.com/video/BV1YG411p7BA) +**[《代码随想录》算法视频公开课](https://programmercarl.com/other/gongkaike.html):[学透哈希表,数组使用有技巧!Leetcode:242.有效的字母异位词](https://www.bilibili.com/video/BV1YG411p7BA),相信结合视频再看本篇题解,更有助于大家对本题的理解**。 + +## 思路 先看暴力的解法,两层for循环,同时还要记录字符是否重复出现,很明显时间复杂度是 O(n^2)。 @@ -88,12 +89,10 @@ public: * 时间复杂度: O(n) * 空间复杂度: O(1) - - ## 其他语言版本 +### Java: -Java: ```java /** * 242. 有效的字母异位词 字典解法 @@ -121,7 +120,7 @@ class Solution { } ``` -Python: +### Python: ```python class Solution: @@ -165,7 +164,7 @@ class Solution(object): return a_count == b_count ``` -Go: +### Go: ```go func isAnagram(s string, t string) bool { @@ -182,7 +181,7 @@ func isAnagram(s string, t string) bool { } ``` -javaScript: +### JavaScript: ```js /** @@ -218,7 +217,7 @@ var isAnagram = function(s, t) { }; ``` -TypeScript: +### TypeScript: ```typescript function isAnagram(s: string, t: string): boolean { @@ -233,7 +232,7 @@ function isAnagram(s: string, t: string): boolean { }; ``` -Swift: +### Swift: ```Swift func isAnagram(_ s: String, _ t: String) -> Bool { @@ -257,7 +256,8 @@ func isAnagram(_ s: String, _ t: String) -> Bool { } ``` -PHP: +### PHP: + ```php class Solution { /** @@ -292,7 +292,8 @@ class Solution { } ``` -Rust: +### Rust: + ```rust impl Solution { pub fn is_anagram(s: String, t: String) -> bool { @@ -312,8 +313,8 @@ impl Solution { } ``` +### Scala: -Scala: ```scala object Solution { def isAnagram(s: String, t: String): Boolean = { @@ -337,8 +338,8 @@ object Solution { } ``` +### C#: -C#: ```csharp public bool IsAnagram(string s, string t) { int sl=s.Length,tl=t.Length; @@ -360,11 +361,12 @@ C#: ## 相关题目 * [383.赎金信](https://programmercarl.com/0383.%E8%B5%8E%E9%87%91%E4%BF%A1.html) -* 49.字母异位词分组 -* 438.找到字符串中所有字母异位词 +* [49.字母异位词分组](https://leetcode.cn/problems/group-anagrams/) +* [438.找到字符串中所有字母异位词](https://leetcode.cn/problems/find-all-anagrams-in-a-string/)

+ From 19dfa98e4f936f4b5f73886e6c1503c07f913bf8 Mon Sep 17 00:00:00 2001 From: jinbudaily <18336218010@163.com> Date: Wed, 19 Jul 2023 14:30:12 +0800 Subject: [PATCH 045/122] =?UTF-8?q?=E6=9B=B4=E6=96=B0=200349.=E4=B8=A4?= =?UTF-8?q?=E4=B8=AA=E6=95=B0=E7=BB=84=E7=9A=84=E4=BA=A4=E9=9B=86=20?= =?UTF-8?q?=E6=8E=92=E7=89=88=E6=A0=BC=E5=BC=8F=E4=BF=AE=E5=A4=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- problems/0349.两个数组的交集.md | 39 +++++++++++++++++++-------------- 1 file changed, 22 insertions(+), 17 deletions(-) diff --git a/problems/0349.两个数组的交集.md b/problems/0349.两个数组的交集.md index c2f6ef46..8daf5a35 100644 --- a/problems/0349.两个数组的交集.md +++ b/problems/0349.两个数组的交集.md @@ -10,7 +10,7 @@ > 如果哈希值比较少、特别分散、跨度非常大,使用数组就造成空间的极大浪费! -## 349. 两个数组的交集 +# 349. 两个数组的交集 [力扣题目链接](https://leetcode.cn/problems/intersection-of-two-arrays/) @@ -22,9 +22,11 @@ 输出结果中的每个元素一定是唯一的。 我们可以不考虑输出结果的顺序。 -## 思路 +## 算法公开课 -关于本题,我录制了讲解视频:[学透哈希表,set使用有技巧!Leetcode:349. 两个数组的交集](https://www.bilibili.com/video/BV1ba411S7wu),看视频配合题解,事半功倍。 +**[《代码随想录》算法视频公开课](https://programmercarl.com/other/gongkaike.html)::[学透哈希表,set使用有技巧!Leetcode:349. 两个数组的交集](https://www.bilibili.com/video/BV1ba411S7wu),相信结合视频再看本篇题解,更有助于大家对本题的理解**。 + +## 思路 这道题目,主要要学会使用一种哈希数据结构:unordered_set,这个数据结构可以解决很多类似的问题。 @@ -118,8 +120,7 @@ public: ## 其他语言版本 - -Java: +### Java: ```Java import java.util.HashSet; @@ -159,8 +160,9 @@ class Solution { } ``` -Python3: +### Python3: (版本一) 使用字典和集合 + ```python class Solution: def intersection(self, nums1: List[int], nums2: List[int]) -> List[int]: @@ -206,7 +208,8 @@ class Solution: ``` -Go: +### Go: + ```go func intersection(nums1 []int, nums2 []int) []int { set:=make(map[int]struct{},0) // 用map模拟set @@ -227,7 +230,7 @@ func intersection(nums1 []int, nums2 []int) []int { } ``` -javaScript: +### JavaScript: ```js /** @@ -255,7 +258,7 @@ var intersection = function(nums1, nums2) { }; ``` -TypeScript: +### TypeScript: 版本一(正常解法): @@ -280,7 +283,7 @@ function intersection(nums1: number[], nums2: number[]): number[] { }; ``` -Swift: +### Swift: ```swift func intersection(_ nums1: [Int], _ nums2: [Int]) -> [Int] { @@ -298,7 +301,8 @@ func intersection(_ nums1: [Int], _ nums2: [Int]) -> [Int] { } ``` -PHP: +### PHP: + ```php class Solution { /** @@ -327,7 +331,8 @@ class Solution { } ``` -Rust: +### Rust: + ```rust use std::collections::HashSet; impl Solution { @@ -363,7 +368,8 @@ impl Solution { } ``` -C: +### C: + ```C int* intersection1(int* nums1, int nums1Size, int* nums2, int nums2Size, int* returnSize){ @@ -394,7 +400,7 @@ int* intersection1(int* nums1, int nums1Size, int* nums2, int nums2Size, int* re } ``` -Scala: +### Scala: 正常解法: ```scala @@ -439,8 +445,8 @@ object Solution { ``` +### C#: -C#: ```csharp public int[] Intersection(int[] nums1, int[] nums2) { if(nums1==null||nums1.Length==0||nums2==null||nums1.Length==0) @@ -461,11 +467,10 @@ C#: ``` ## 相关题目 -* 350.两个数组的交集 II +* [350.两个数组的交集 II](https://leetcode.cn/problems/intersection-of-two-arrays-ii/)

- From 764b3e9e51608baf17183a5e36cab0888a6e46f9 Mon Sep 17 00:00:00 2001 From: jinbudaily <18336218010@163.com> Date: Wed, 19 Jul 2023 14:34:27 +0800 Subject: [PATCH 046/122] =?UTF-8?q?=E6=9B=B4=E6=96=B0=200202.=E5=BF=AB?= =?UTF-8?q?=E4=B9=90=E6=95=B0=20=E6=8E=92=E7=89=88=E6=A0=BC=E5=BC=8F?= =?UTF-8?q?=E4=BF=AE=E5=A4=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- problems/0202.快乐数.md | 42 +++++++++++++++++++++++------------------ 1 file changed, 24 insertions(+), 18 deletions(-) diff --git a/problems/0202.快乐数.md b/problems/0202.快乐数.md index 7fe8cd8d..4a77e2b6 100644 --- a/problems/0202.快乐数.md +++ b/problems/0202.快乐数.md @@ -28,7 +28,7 @@ 6^2 + 8^2 = 100 1^2 + 0^2 + 0^2 = 1 -# 思路 +## 思路 这道题目看上去貌似一道数学问题,其实并不是! @@ -80,10 +80,10 @@ public: -# 其他语言版本 +## 其他语言版本 +### Java: -Java: ```java class Solution { public boolean isHappy(int n) { @@ -107,8 +107,9 @@ class Solution { } ``` -Python: +### Python: (版本一)使用集合 + ```python class Solution: def isHappy(self, n: int) -> bool: @@ -131,7 +132,7 @@ class Solution: n, r = divmod(n, 10) new_num += r ** 2 return new_num - ``` +``` (版本二)使用集合 ```python class Solution: @@ -146,7 +147,7 @@ class Solution: if new_num==1: return True else: n = new_num return False -``` + ``` (版本三)使用数组 ```python class Solution: @@ -161,7 +162,7 @@ class Solution: if new_num==1: return True else: n = new_num return False -``` + ``` (版本四)使用快慢指针 ```python class Solution: @@ -180,7 +181,7 @@ class Solution: n, r = divmod(n, 10) new_num += r ** 2 return new_num -``` + ``` (版本五)使用集合+精简 ```python class Solution: @@ -192,7 +193,7 @@ class Solution: return False seen.add(n) return True -``` + ``` (版本六)使用数组+精简 ```python class Solution: @@ -204,8 +205,9 @@ class Solution: return False seen.append(n) return True -``` -Go: + ``` +### Go: + ```go func isHappy(n int) bool { m := make(map[int]bool) @@ -225,7 +227,7 @@ func getSum(n int) int { } ``` -javaScript: +### JavaScript: ```js var isHappy = function (n) { @@ -303,7 +305,7 @@ var isHappy = function(n) { }; ``` -TypeScript: +### TypeScript: ```typescript function isHappy(n: number): boolean { @@ -322,7 +324,7 @@ function isHappy(n: number): boolean { }; ``` -Swift: +### Swift: ```swift // number 每个位置上的数字的平方和 @@ -355,7 +357,8 @@ func isHappy(_ n: Int) -> Bool { } ``` -PHP: +### PHP: + ```php class Solution { /** @@ -386,7 +389,8 @@ class Solution { } ``` -Rust: +### Rust: + ```Rust use std::collections::HashSet; impl Solution { @@ -416,7 +420,8 @@ impl Solution { } ``` -C: +### C: + ```C typedef struct HashNodeTag { int key; /* num */ @@ -473,8 +478,8 @@ object Solution { } ``` +### C#: -C#: ```csharp public class Solution { private int getSum(int n) { @@ -500,3 +505,4 @@ public class Solution { + From 23950d1c3e8541420eaca3f55f0896a84d3ba007 Mon Sep 17 00:00:00 2001 From: jinbudaily <18336218010@163.com> Date: Wed, 19 Jul 2023 14:43:14 +0800 Subject: [PATCH 047/122] =?UTF-8?q?=E6=9B=B4=E6=96=B0=20001.=E4=B8=A4?= =?UTF-8?q?=E6=95=B0=E4=B9=8B=E5=92=8C=20=E6=8E=92=E7=89=88=E6=A0=BC?= =?UTF-8?q?=E5=BC=8F=E4=BF=AE=E5=A4=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- problems/0001.两数之和.md | 41 ++++++++++++++++++++++----------------- 1 file changed, 23 insertions(+), 18 deletions(-) diff --git a/problems/0001.两数之和.md b/problems/0001.两数之和.md index ca62e3ed..e3fb0fb5 100644 --- a/problems/0001.两数之和.md +++ b/problems/0001.两数之和.md @@ -5,7 +5,7 @@

参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!

-## 1. 两数之和 +# 1. 两数之和 [力扣题目链接](https://leetcode.cn/problems/two-sum/) @@ -21,11 +21,13 @@ 所以返回 [0, 1] +## 算法公开课 + +**[《代码随想录》算法视频公开课](https://programmercarl.com/other/gongkaike.html):[梦开始的地方,Leetcode:1.两数之和](https://www.bilibili.com/video/BV1aT41177mK),相信结合视频再看本篇题解,更有助于大家对本题的理解**。 + ## 思路 -建议看一下我录的这期视频:[梦开始的地方,Leetcode:1.两数之和](https://www.bilibili.com/video/BV1aT41177mK),结合本题解来学习,事半功倍。 - 很明显暴力的解法是两层for循环查找,时间复杂度是O(n^2)。 建议大家做这道题目之前,先做一下这两道 @@ -128,8 +130,8 @@ public: ## 其他语言版本 +### Java: -Java: ```java public int[] twoSum(int[] nums, int target) { int[] res = new int[2]; @@ -150,8 +152,9 @@ public int[] twoSum(int[] nums, int target) { } ``` -Python: +### Python: (版本一) 使用字典 + ```python class Solution: def twoSum(self, nums: List[int], target: int) -> List[int]: @@ -211,7 +214,7 @@ class Solution: return [i,j] ``` -Go: +### Go: ```go // 暴力解法 @@ -242,7 +245,7 @@ func twoSum(nums []int, target int) []int { } ``` -Rust +### Rust: ```rust use std::collections::HashMap; @@ -263,9 +266,7 @@ impl Solution { } } ``` -Rust - -``` +```rust use std::collections::HashMap; impl Solution { @@ -284,7 +285,7 @@ impl Solution { } ``` -Javascript +### Javascript: ```javascript var twoSum = function (nums, target) { @@ -299,7 +300,7 @@ var twoSum = function (nums, target) { }; ``` -TypeScript: +### TypeScript: ```typescript function twoSum(nums: number[], target: number): number[] { @@ -317,7 +318,7 @@ function twoSum(nums: number[], target: number): number[] { }; ``` -php +### php: ```php function twoSum(array $nums, int $target): array @@ -337,7 +338,8 @@ function twoSum(array $nums, int $target): array } ``` -Swift: +### Swift: + ```swift func twoSum(_ nums: [Int], _ target: Int) -> [Int] { // 值: 下标 @@ -353,8 +355,8 @@ func twoSum(_ nums: [Int], _ target: Int) -> [Int] { } ``` +### Scala: -Scala: ```scala object Solution { // 导入包 @@ -377,7 +379,8 @@ object Solution { } ``` -C#: +### C#: + ```csharp public class Solution { public int[] TwoSum(int[] nums, int target) { @@ -396,7 +399,8 @@ public class Solution { } ``` -Dart: +### Dart: + ```dart List twoSum(List nums, int target) { var tmp = []; @@ -411,7 +415,8 @@ List twoSum(List nums, int target) { } ``` -C: +### C: + ```c From 2948791011238baa02f6beda8bb496e8c52fb6de Mon Sep 17 00:00:00 2001 From: jinbudaily <18336218010@163.com> Date: Wed, 19 Jul 2023 14:47:02 +0800 Subject: [PATCH 048/122] =?UTF-8?q?=E6=9B=B4=E6=96=B0=200454.=E5=9B=9B?= =?UTF-8?q?=E6=95=B0=E7=9B=B8=E5=8A=A0II=20=E6=8E=92=E7=89=88=E6=A0=BC?= =?UTF-8?q?=E5=BC=8F=E4=BF=AE=E5=A4=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- problems/0454.四数相加II.md | 30 ++++++++++++++++++------------ 1 file changed, 18 insertions(+), 12 deletions(-) diff --git a/problems/0454.四数相加II.md b/problems/0454.四数相加II.md index 4a16d4f4..90c37334 100644 --- a/problems/0454.四数相加II.md +++ b/problems/0454.四数相加II.md @@ -34,10 +34,12 @@ 1. (0, 0, 0, 1) -> A[0] + B[0] + C[0] + D[1] = 1 + (-2) + (-1) + 2 = 0 2. (1, 1, 0, 0) -> A[1] + B[1] + C[0] + D[0] = 2 + (-1) + (-1) + 0 = 0 +## 算法公开课 -# 思路 +**[《代码随想录》算法视频公开课](https://programmercarl.com/other/gongkaike.html):[学透哈希表,map使用有技巧!LeetCode:454.四数相加II](https://www.bilibili.com/video/BV1Md4y1Q7Yh),相信结合视频再看本篇题解,更有助于大家对本题的理解**。 -本题视频讲解:[学透哈希表,map使用有技巧!LeetCode:454.四数相加II](https://www.bilibili.com/video/BV1Md4y1Q7Yh),结合视频在看本题解,事半功倍。 + +## 思路 本题咋眼一看好像和[0015.三数之和](https://programmercarl.com/0015.三数之和.html),[0018.四数之和](https://programmercarl.com/0018.四数之和.html)差不多,其实差很多。 @@ -92,8 +94,8 @@ public: ## 其他语言版本 +### Java: -Java: ```Java class Solution { public int fourSumCount(int[] nums1, int[] nums2, int[] nums3, int[] nums4) { @@ -117,8 +119,9 @@ class Solution { } ``` -Python: +### Python: (版本一) 使用字典 + ```python class Solution(object): def fourSumCount(self, nums1, nums2, nums3, nums4): @@ -179,7 +182,7 @@ class Solution: return cnt ``` -Go: +### Go: ```go func fourSumCount(nums1 []int, nums2 []int, nums3 []int, nums4 []int) int { @@ -201,7 +204,7 @@ func fourSumCount(nums1 []int, nums2 []int, nums3 []int, nums4 []int) int { } ``` -javaScript: +### JavaScript: ```js /** @@ -233,7 +236,7 @@ var fourSumCount = function(nums1, nums2, nums3, nums4) { }; ``` -TypeScript: +### TypeScript: ```typescript function fourSumCount(nums1: number[], nums2: number[], nums3: number[], nums4: number[]): number { @@ -258,7 +261,7 @@ function fourSumCount(nums1: number[], nums2: number[], nums3: number[], nums4: }; ``` -PHP: +### PHP: ```php class Solution { @@ -291,8 +294,8 @@ class Solution { } ``` +### Swift: -Swift: ```swift func fourSumCount(_ nums1: [Int], _ nums2: [Int], _ nums3: [Int], _ nums4: [Int]) -> Int { // ab和: ab和出现次数 @@ -316,7 +319,8 @@ func fourSumCount(_ nums1: [Int], _ nums2: [Int], _ nums3: [Int], _ nums4: [Int] } ``` -Rust: +### Rust: + ```rust use std::collections::HashMap; impl Solution { @@ -342,8 +346,8 @@ impl Solution { } ``` +### Scala: -Scala: ```scala object Solution { // 导包 @@ -380,7 +384,8 @@ object Solution { } ``` -C#: +### C#: + ```csharp public int FourSumCount(int[] nums1, int[] nums2, int[] nums3, int[] nums4) { Dictionary dic = new Dictionary(); @@ -411,3 +416,4 @@ public int FourSumCount(int[] nums1, int[] nums2, int[] nums3, int[] nums4) { + From 0922ede8c7ce3fedbd7494834beb224aa3da6311 Mon Sep 17 00:00:00 2001 From: jinbudaily <18336218010@163.com> Date: Wed, 19 Jul 2023 14:49:56 +0800 Subject: [PATCH 049/122] =?UTF-8?q?=E6=9B=B4=E6=96=B0=200383.=E8=B5=8E?= =?UTF-8?q?=E9=87=91=E4=BF=A1=20=E6=8E=92=E7=89=88=E6=A0=BC=E5=BC=8F?= =?UTF-8?q?=E4=BF=AE=E5=A4=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- problems/0383.赎金信.md | 28 ++++++++++++++++------------ 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/problems/0383.赎金信.md b/problems/0383.赎金信.md index e74cdf71..8122240e 100644 --- a/problems/0383.赎金信.md +++ b/problems/0383.赎金信.md @@ -34,7 +34,7 @@ canConstruct("aa", "aab") -> true * 第二点 “你可以假设两个字符串均只含有小写字母。” *说明只有小写字母*,这一点很重要 -## 暴力解法 +### 暴力解法 那么第一个思路其实就是暴力枚举了,两层for循环,不断去寻找,代码如下: @@ -66,7 +66,7 @@ public: 这里时间复杂度是比较高的,而且里面还有一个字符串删除也就是erase的操作,也是费时的,当然这段代码也可以过这道题。 -## 哈希解法 +### 哈希解法 因为题目所只有小写字母,那可以采用空间换取时间的哈希策略, 用一个长度为26的数组还记录magazine里字母出现的次数。 @@ -112,8 +112,8 @@ public: ## 其他语言版本 +### Java: -Java: ```Java class Solution { public boolean canConstruct(String ransomNote, String magazine) { @@ -146,8 +146,9 @@ class Solution { ``` -Python: +### Python: (版本一)使用数组 + ```python class Solution: def canConstruct(self, ransomNote: str, magazine: str) -> bool: @@ -213,7 +214,7 @@ class Solution: return all(ransomNote.count(c) <= magazine.count(c) for c in set(ransomNote)) ``` -Go: +### Go: ```go func canConstruct(ransomNote string, magazine string) bool { @@ -231,7 +232,7 @@ func canConstruct(ransomNote string, magazine string) bool { } ``` -javaScript: +### JavaScript: ```js /** @@ -254,7 +255,7 @@ var canConstruct = function(ransomNote, magazine) { }; ``` -TypeScript: +### TypeScript: ```typescript function canConstruct(ransomNote: string, magazine: string): boolean { @@ -275,8 +276,8 @@ function canConstruct(ransomNote: string, magazine: string): boolean { }; ``` +### PHP: -PHP: ```php class Solution { /** @@ -301,7 +302,8 @@ class Solution { } ``` -Swift: +### Swift: + ```swift func canConstruct(_ ransomNote: String, _ magazine: String) -> Bool { var record = Array(repeating: 0, count: 26); @@ -324,7 +326,8 @@ func canConstruct(_ ransomNote: String, _ magazine: String) -> Bool { } ``` -Rust: +### Rust: + ```rust impl Solution { pub fn can_construct(ransom_note: String, magazine: String) -> bool { @@ -347,7 +350,7 @@ impl Solution { } ``` -Scala: +### Scala: 版本一: 使用数组作为哈希表 ```scala @@ -411,8 +414,8 @@ object Solution { } ``` +### C#: -C#: ```csharp public bool CanConstruct(string ransomNote, string magazine) { if(ransomNote.Length > magazine.Length) return false; @@ -434,3 +437,4 @@ public bool CanConstruct(string ransomNote, string magazine) { + From eb2cdf24bf03dd143072a4260fb11b76ececcc37 Mon Sep 17 00:00:00 2001 From: jinbudaily <18336218010@163.com> Date: Wed, 19 Jul 2023 14:55:09 +0800 Subject: [PATCH 050/122] =?UTF-8?q?=E6=9B=B4=E6=96=B0=200015.=E4=B8=89?= =?UTF-8?q?=E6=95=B0=E4=B9=8B=E5=92=8C=20=E6=8E=92=E7=89=88=E6=A0=BC?= =?UTF-8?q?=E5=BC=8F=E4=BF=AE=E5=A4=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- problems/0015.三数之和.md | 55 +++++++++++++++++++++++---------------- 1 file changed, 32 insertions(+), 23 deletions(-) diff --git a/problems/0015.三数之和.md b/problems/0015.三数之和.md index 9cca779b..4951c90c 100644 --- a/problems/0015.三数之和.md +++ b/problems/0015.三数之和.md @@ -26,14 +26,15 @@ [-1, -1, 2] ] +## 算法公开课 -# 思路 - -针对本题,我录制了视频讲解:[梦破碎的地方!| LeetCode:15.三数之和](https://www.bilibili.com/video/BV1GW4y127qo),结合本题解一起看,事半功倍! +**[《代码随想录》算法视频公开课](https://programmercarl.com/other/gongkaike.html):[梦破碎的地方!| LeetCode:15.三数之和](https://www.bilibili.com/video/BV1GW4y127qo),相信结合视频再看本篇题解,更有助于大家对本题的理解**。 **注意[0, 0, 0, 0] 这组数据** -## 哈希解法 +## 思路 + +### 哈希解法 两层for循环就可以确定 a 和b 的数值了,可以使用哈希法来确定 0-(a+b) 是否在 数组里出现过,其实这个思路是正确的,但是我们有一个非常棘手的问题,就是题目中说的不可以包含重复的三元组。 @@ -87,7 +88,7 @@ public: * 空间复杂度: O(n),额外的 set 开销 -## 双指针 +### 双指针 **其实这道题目使用哈希法并不十分合适**,因为在去重的操作中有很多细节需要注意,在面试中很难直接写出没有bug的代码。 @@ -166,9 +167,9 @@ public: * 空间复杂度: O(1) -## 去重逻辑的思考 +### 去重逻辑的思考 -### a的去重 +#### a的去重 说道去重,其实主要考虑三个数的去重。 a, b ,c, 对应的就是 nums[i],nums[left],nums[right] @@ -188,7 +189,7 @@ a 如果重复了怎么办,a是nums里遍历的元素,那么应该直接跳 if (nums[i] == nums[i + 1]) { // 去重操作 continue; } -``` +``` 那就我们就把 三元组中出现重复元素的情况直接pass掉了。 例如{-1, -1 ,2} 这组数据,当遍历到第一个-1 的时候,判断 下一个也是-1,那这组数据就pass了。 @@ -208,7 +209,7 @@ if (i > 0 && nums[i] == nums[i - 1]) { 这是一个非常细节的思考过程。 -### b与c的去重 +#### b与c的去重 很多同学写本题的时候,去重的逻辑多加了 对right 和left 的去重:(代码中注释部分) @@ -225,7 +226,7 @@ while (right > left) { } else { } } -``` +``` 但细想一下,这种去重其实对提升程序运行效率是没有帮助的。 @@ -238,7 +239,7 @@ while (right > left) { 所以这种去重 是可以不加的。 仅仅是 把去重的逻辑提前了而已。 -# 思考题 +## 思考题 既然三数之和可以使用双指针法,我们之前讲过的[1.两数之和](https://programmercarl.com/0001.两数之和.html),可不可以使用双指针法呢? @@ -254,8 +255,8 @@ while (right > left) { ## 其他语言版本 +### Java: -Java: ```Java class Solution { public List> threeSum(int[] nums) { @@ -297,8 +298,9 @@ class Solution { } ``` -Python: +### Python: (版本一) 双指针 + ```Python class Solution: def threeSum(self, nums: List[int]) -> List[List[int]]: @@ -366,7 +368,7 @@ class Solution: return result ``` -Go: +### Go: ```Go func threeSum(nums []int) [][]int { @@ -407,7 +409,7 @@ func threeSum(nums []int) [][]int { } ``` -javaScript: +### JavaScript: ```js var threeSum = function(nums) { @@ -512,7 +514,7 @@ var threeSum = function (nums) { }; ``` -TypeScript: +### TypeScript: ```typescript function threeSum(nums: number[]): number[][] { @@ -553,7 +555,8 @@ function threeSum(nums: number[]): number[][] { }; ``` -ruby: +### Ruby: + ```ruby def is_valid(strs) symbol_map = {')' => '(', '}' => '{', ']' => '['} @@ -571,8 +574,8 @@ def is_valid(strs) end ``` +### PHP: -PHP: ```php class Solution { /** @@ -613,7 +616,8 @@ class Solution { } ``` -Swift: +### Swift: + ```swift // 双指针法 func threeSum(_ nums: [Int]) -> [[Int]] { @@ -654,7 +658,8 @@ func threeSum(_ nums: [Int]) -> [[Int]] { } ``` -Rust: +### Rust: + ```Rust // 哈希解法 use std::collections::HashSet; @@ -718,7 +723,8 @@ impl Solution { } ``` -C: +### C: + ```C //qsort辅助cmp函数 int cmp(const void* ptr1, const void* ptr2) { @@ -792,7 +798,8 @@ int** threeSum(int* nums, int numsSize, int* returnSize, int** returnColumnSizes } ``` -C#: +### C#: + ```csharp public class Solution { @@ -850,7 +857,8 @@ public class Solution } } ``` -Scala: +### Scala: + ```scala object Solution { // 导包 @@ -898,3 +906,4 @@ object Solution { + From 3fe673d804209e55705b2b7206d86e3fc6e87e18 Mon Sep 17 00:00:00 2001 From: jinbudaily <18336218010@163.com> Date: Wed, 19 Jul 2023 14:59:05 +0800 Subject: [PATCH 051/122] =?UTF-8?q?=E6=9B=B4=E6=96=B0=200018.=E5=9B=9B?= =?UTF-8?q?=E6=95=B0=E4=B9=8B=E5=92=8C=20=E6=8E=92=E7=89=88=E6=A0=BC?= =?UTF-8?q?=E5=BC=8F=E4=BF=AE=E5=A4=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- problems/0018.四数之和.md | 41 +++++++++++++++++++++------------------ 1 file changed, 22 insertions(+), 19 deletions(-) diff --git a/problems/0018.四数之和.md b/problems/0018.四数之和.md index a4d41d9b..28c20b7a 100644 --- a/problems/0018.四数之和.md +++ b/problems/0018.四数之和.md @@ -27,9 +27,11 @@ [-2, 0, 0, 2] ] -# 思路 +## 算法公开课 -针对本题,我录制了视频讲解:[难在去重和剪枝!| LeetCode:18. 四数之和](https://www.bilibili.com/video/BV1DS4y147US),结合本题解一起看,事半功倍! +**[《代码随想录》算法视频公开课](https://programmercarl.com/other/gongkaike.html):[难在去重和剪枝!| LeetCode:18. 四数之和](https://www.bilibili.com/video/BV1DS4y147US),相信结合视频再看本篇题解,更有助于大家对本题的理解**。 + +## 思路 四数之和,和[15.三数之和](https://programmercarl.com/0015.三数之和.html)是一个思路,都是使用双指针法, 基本解法就是在[15.三数之和](https://programmercarl.com/0015.三数之和.html) 的基础上再套一层for循环。 @@ -141,22 +143,16 @@ if (nums[k] + nums[i] > target && nums[k] + nums[i] >= 0) { if (nums[k] + nums[i] > target && nums[i] >= 0) { break; } -``` +``` 因为只要 nums[k] + nums[i] > target,那么 nums[i] 后面的数都是正数的话,就一定 不符合条件了。 不过这种剪枝 其实有点 小绕,大家能够理解 文章给的完整代码的剪枝 就够了。 - - - - - - ## 其他语言版本 +### Java: -Java: ```Java class Solution { public List> fourSum(int[] nums, int target) { @@ -206,8 +202,9 @@ class Solution { } ``` -Python: +### Python: (版本一) 双指针 + ```python class Solution: def fourSum(self, nums: List[int], target: int) -> List[List[int]]: @@ -273,7 +270,8 @@ class Solution(object): ``` -Go: +### Go: + ```go func fourSum(nums []int, target int) [][]int { if len(nums) < 4 { @@ -323,7 +321,7 @@ func fourSum(nums []int, target int) [][]int { } ``` -javaScript: +### JavaScript: ```js /** @@ -359,7 +357,7 @@ var fourSum = function(nums, target) { }; ``` -TypeScript: +### TypeScript: ```typescript function fourSum(nums: number[], target: number): number[][] { @@ -400,7 +398,7 @@ function fourSum(nums: number[], target: number): number[][] { }; ``` -PHP: +### PHP: ```php class Solution { @@ -445,7 +443,8 @@ class Solution { } ``` -Swift: +### Swift: + ```swift func fourSum(_ nums: [Int], _ target: Int) -> [[Int]] { var res = [[Int]]() @@ -493,7 +492,8 @@ func fourSum(_ nums: [Int], _ target: Int) -> [[Int]] { } ``` -C#: +### C#: + ```csharp public class Solution { @@ -555,7 +555,8 @@ public class Solution } ``` -Rust: +### Rust: + ```Rust use std::cmp::Ordering; impl Solution { @@ -603,7 +604,8 @@ impl Solution { } ``` -Scala: +### Scala: + ```scala object Solution { // 导包 @@ -651,3 +653,4 @@ object Solution { + From ddee6adbbba4db9466cf720307b2e44f10e22140 Mon Sep 17 00:00:00 2001 From: jinbudaily <18336218010@163.com> Date: Wed, 19 Jul 2023 15:01:01 +0800 Subject: [PATCH 052/122] =?UTF-8?q?=E6=9B=B4=E6=96=B0=20=E5=93=88=E5=B8=8C?= =?UTF-8?q?=E8=A1=A8=E6=80=BB=E7=BB=93=20=E6=8E=92=E7=89=88=E6=A0=BC?= =?UTF-8?q?=E5=BC=8F=E4=BF=AE=E5=A4=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- problems/哈希表总结.md | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/problems/哈希表总结.md b/problems/哈希表总结.md index 9ee84f99..67506363 100644 --- a/problems/哈希表总结.md +++ b/problems/哈希表总结.md @@ -7,8 +7,10 @@ > 哈希表总结篇如约而至 +# 哈希表总结篇 -# 哈希表理论基础 + +## 哈希表理论基础 在[关于哈希表,你该了解这些!](https://programmercarl.com/哈希表理论基础.html)中,我们介绍了哈希表的基础理论知识,不同于枯燥的讲解,这里介绍了都是对刷题有帮助的理论知识点。 @@ -32,9 +34,9 @@ **只有对这些数据结构的底层实现很熟悉,才能灵活使用,否则很容易写出效率低下的程序**。 -# 哈希表经典题目 +## 哈希表经典题目 -## 数组作为哈希表 +### 数组作为哈希表 一些应用场景就是为数组量身定做的。 @@ -51,7 +53,7 @@ **上面两道题目用map确实可以,但使用map的空间消耗要比数组大一些,因为map要维护红黑树或者符号表,而且还要做哈希函数的运算。所以数组更加简单直接有效!** -## set作为哈希表 +### set作为哈希表 在[349. 两个数组的交集](https://programmercarl.com/0349.两个数组的交集.html)中我们给出了什么时候用数组就不行了,需要用set。 @@ -75,7 +77,7 @@ std::set和std::multiset底层实现都是红黑树,std::unordered_set的底 在[202.快乐数](https://programmercarl.com/0202.快乐数.html)中,我们再次使用了unordered_set来判断一个数是否重复出现过。 -## map作为哈希表 +### map作为哈希表 在[1.两数之和](https://programmercarl.com/0001.两数之和.html)中map正式登场。 @@ -110,7 +112,7 @@ std::unordered_map 底层实现为哈希,std::map 和std::multimap 的底层 所以18. 四数之和,15.三数之和都推荐使用双指针法! -# 总结 +## 总结 对于哈希表的知识相信很多同学都知道,但是没有成体系。 @@ -123,9 +125,8 @@ std::unordered_map 底层实现为哈希,std::map 和std::multimap 的底层 - -

+ From 00ef6084c6ea18933e7a63923aad71addee70c6e Mon Sep 17 00:00:00 2001 From: jinbudaily <18336218010@163.com> Date: Wed, 19 Jul 2023 15:32:11 +0800 Subject: [PATCH 053/122] =?UTF-8?q?=E6=9B=B4=E6=96=B0=200344.=E5=8F=8D?= =?UTF-8?q?=E8=BD=AC=E5=AD=97=E7=AC=A6=E4=B8=B2=20=E6=8E=92=E7=89=88?= =?UTF-8?q?=E6=A0=BC=E5=BC=8F=E4=BF=AE=E5=A4=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- problems/0344.反转字符串.md | 35 +++++++++++++++++++++-------------- 1 file changed, 21 insertions(+), 14 deletions(-) diff --git a/problems/0344.反转字符串.md b/problems/0344.反转字符串.md index 1c74f9aa..8a4fed45 100644 --- a/problems/0344.反转字符串.md +++ b/problems/0344.反转字符串.md @@ -26,10 +26,12 @@ 输入:["H","a","n","n","a","h"] 输出:["h","a","n","n","a","H"] +## 算法公开课 -# 思路 +**[《代码随想录》算法视频公开课](https://programmercarl.com/other/gongkaike.html):[字符串基础操作! | LeetCode:344.反转字符串](https://www.bilibili.com/video/BV1fV4y17748),相信结合视频再看本篇题解,更有助于大家对本题的理解**。 -针对本题,我录制了视频讲解:[字符串基础操作! | LeetCode:344.反转字符串](https://www.bilibili.com/video/BV1fV4y17748),结合本题解一起看,事半功倍! + +## 思路 先说一说题外话: @@ -138,8 +140,8 @@ public: ## 其他语言版本 +### Java: -Java: ```Java class Solution { public void reverseString(char[] s) { @@ -173,8 +175,9 @@ class Solution { ``` -Python: +### Python: (版本一) 双指针 + ```python class Solution: def reverseString(self, s: List[str]) -> None: @@ -247,7 +250,8 @@ class Solution: s[:] = [s[i] for i in range(len(s) - 1, -1, -1)] ``` -Go: +### Go: + ```Go func reverseString(s []byte) { left := 0 @@ -260,7 +264,7 @@ func reverseString(s []byte) { } ``` -javaScript: +### JavaScript: ```js /** @@ -278,7 +282,7 @@ var reverse = function(s) { }; ``` -TypeScript: +### TypeScript: ```typescript /** @@ -299,7 +303,7 @@ function reverseString(s: string[]): void { }; ``` -Swift: +### Swift: ```swift // 双指针 - 元组 @@ -316,7 +320,8 @@ func reverseString(_ s: inout [Character]) { ``` -Rust: +### Rust: + ```Rust impl Solution { pub fn reverse_string(s: &mut Vec) { @@ -332,7 +337,8 @@ impl Solution { } ``` -C: +### C: + ```c void reverseString(char* s, int sSize){ int left = 0; @@ -347,7 +353,8 @@ void reverseString(char* s, int sSize){ } ``` -C#: +### C#: + ```csharp public class Solution { @@ -361,8 +368,8 @@ public class Solution } ``` +### PHP: -PHP: ```php // 双指针 // 一: @@ -392,7 +399,8 @@ function reverse(&$s, $start, $end) { } ``` -Scala: +### Scala: + ```scala object Solution { def reverseString(s: Array[Char]): Unit = { @@ -411,4 +419,3 @@ object Solution { - From 5cb250100b49e1b8109ddf01ba2109b257094b47 Mon Sep 17 00:00:00 2001 From: jinbudaily <18336218010@163.com> Date: Wed, 19 Jul 2023 15:37:57 +0800 Subject: [PATCH 054/122] =?UTF-8?q?=E6=9B=B4=E6=96=B0=200541.=E5=8F=8D?= =?UTF-8?q?=E8=BD=AC=E5=AD=97=E7=AC=A6=E4=B8=B2=20=E6=8E=92=E7=89=88?= =?UTF-8?q?=E6=A0=BC=E5=BC=8F=E4=BF=AE=E5=A4=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- problems/0541.反转字符串II.md | 33 +++++++++++++++++---------------- 1 file changed, 17 insertions(+), 16 deletions(-) diff --git a/problems/0541.反转字符串II.md b/problems/0541.反转字符串II.md index 179395b3..80e662f9 100644 --- a/problems/0541.反转字符串II.md +++ b/problems/0541.反转字符串II.md @@ -23,9 +23,11 @@ 输入: s = "abcdefg", k = 2 输出: "bacdfeg" -# 思路 +## 算法公开课 -针对本题,我录制了视频讲解:[字符串操作进阶! | LeetCode:541. 反转字符串II](https://www.bilibili.com/video/BV1dT411j7NN),结合本题解一起看,事半功倍! +**[《代码随想录》算法视频公开课](https://programmercarl.com/other/gongkaike.html):[字符串操作进阶! | LeetCode:541. 反转字符串II](https://www.bilibili.com/video/BV1dT411j7NN),相信结合视频再看本篇题解,更有助于大家对本题的理解**。 + +## 思路 这道题目其实也是模拟,实现题目中规定的反转规则就可以了。 @@ -42,8 +44,6 @@ 那么这里具体反转的逻辑我们要不要使用库函数呢,其实用不用都可以,使用reverse来实现反转也没毛病,毕竟不是解题关键部分。 -# C++代码 - 使用C++库函数reverse的版本如下: ```CPP @@ -129,7 +129,7 @@ public: ## 其他语言版本 -C: +### C: ```c char * reverseStr(char * s, int k){ @@ -152,7 +152,7 @@ char * reverseStr(char * s, int k){ } ``` -Java: +### Java: ```Java //解法一 @@ -256,7 +256,8 @@ class Solution { } } ``` -Python: +### Python: + ```python class Solution: def reverseStr(self, s: str, k: int) -> str: @@ -281,7 +282,7 @@ class Solution: return ''.join(res) ``` -Python3 (v2): +### Python3 (v2): ```python class Solution: @@ -296,7 +297,7 @@ class Solution: return s ``` -Go: +### Go: ```go func reverseStr(s string, k int) string { @@ -325,7 +326,7 @@ func reverse(b []byte) { } ``` -javaScript: +### JavaScript: ```js @@ -346,7 +347,7 @@ var reverseStr = function(s, k) { ``` -TypeScript: +### TypeScript: ```typescript function reverseStr(s: string, k: number): string { @@ -368,7 +369,7 @@ function reverseStr(s: string, k: number): string { }; ``` -Swift: +### Swift: ```swift func reverseStr(_ s: String, _ k: Int) -> String { @@ -388,7 +389,8 @@ func reverseStr(_ s: String, _ k: Int) -> String { } ``` -C#: +### C#: + ```csharp public class Solution { @@ -403,7 +405,7 @@ public class Solution } } ``` -Scala: +### Scala: 版本一: (正常解法) ```scala @@ -469,7 +471,7 @@ object Solution { } ``` -Rust: +### Rust: ```Rust impl Solution { @@ -503,4 +505,3 @@ impl Solution { - From 963eb8fc8e58094388bf6c0f27be7563d7a488b9 Mon Sep 17 00:00:00 2001 From: jinbudaily <18336218010@163.com> Date: Wed, 19 Jul 2023 15:41:59 +0800 Subject: [PATCH 055/122] =?UTF-8?q?=E6=9B=B4=E6=96=B0=20=E5=89=91=E6=8C=87?= =?UTF-8?q?Offer05.=E6=9B=BF=E6=8D=A2=E7=A9=BA=E6=A0=BC=20=E6=8E=92?= =?UTF-8?q?=E7=89=88=E6=A0=BC=E5=BC=8F=E4=BF=AE=E5=A4=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- problems/剑指Offer05.替换空格.md | 29 ++++++++++++++++------------- 1 file changed, 16 insertions(+), 13 deletions(-) diff --git a/problems/剑指Offer05.替换空格.md b/problems/剑指Offer05.替换空格.md index dbad781e..fed08a53 100644 --- a/problems/剑指Offer05.替换空格.md +++ b/problems/剑指Offer05.替换空格.md @@ -15,7 +15,7 @@ 输入:s = "We are happy." 输出:"We%20are%20happy." -# 思路 +## 思路 如果想把这道题目做到极致,就不要只用额外的辅助空间了! @@ -86,7 +86,7 @@ public: * [142.环形链表II](https://programmercarl.com/0142.环形链表II.html) * [344.反转字符串](https://programmercarl.com/0344.反转字符串.html) -# 拓展 +## 拓展 这里也给大家拓展一下字符串和数组有什么差别, @@ -121,7 +121,8 @@ for (int i = 0; i < a.size(); i++) { ## 其他语言版本 -C: +### C: + ```C char* replaceSpace(char* s){ //统计空格数量 @@ -152,8 +153,8 @@ char* replaceSpace(char* s){ } ``` +### Java: -Java: ```Java //使用一个新的对象,复制 str,复制的过程对其判断,是空格则替换,否则直接复制,类似于数组复制 public static String replaceSpace(String s) { @@ -211,8 +212,8 @@ public String replaceSpace(String s) { } ``` +### Go: -Go: ```go // 遍历添加 func replaceSpace(s string) string { @@ -264,9 +265,10 @@ func replaceSpace(s string) string { +### python: + +因为字符串是不可变类型,所以操作字符串需要将其转换为列表,因此空间复杂度不可能为O(1) -python: -#### 因为字符串是不可变类型,所以操作字符串需要将其转换为列表,因此空间复杂度不可能为O(1) (版本一)转换成列表,并且添加相匹配的空间,然后进行填充 ```python class Solution: @@ -328,7 +330,7 @@ class Solution: def replaceSpace(self, s: str) -> str: return s.replace(' ', '%20') ``` -javaScript: +### JavaScript: ```js /** @@ -366,7 +368,7 @@ javaScript: }; ``` -TypeScript: +### TypeScript: ```typescript function replaceSpace(s: string): string { @@ -393,7 +395,7 @@ function replaceSpace(s: string): string { }; ``` -Swift: +### Swift: ```swift func replaceSpace(_ s: String) -> String { @@ -434,7 +436,7 @@ func replaceSpace(_ s: String) -> String { } ``` -Scala: +### Scala: 方式一: 双指针 ```scala @@ -491,8 +493,8 @@ object Solution { } ``` +### PHP: -PHP: ```php function replaceSpace($s){ $sLen = strlen($s); @@ -527,7 +529,7 @@ function spaceLen($s){ } ``` -Rust +### Rust: ```Rust impl Solution { @@ -563,3 +565,4 @@ impl Solution { + From e70ca923440e656d4c62761fcff2ff40e9c17b32 Mon Sep 17 00:00:00 2001 From: jinbudaily <18336218010@163.com> Date: Wed, 19 Jul 2023 15:47:12 +0800 Subject: [PATCH 056/122] =?UTF-8?q?=E6=9B=B4=E6=96=B0=200151.=E5=8F=8D?= =?UTF-8?q?=E8=BD=AC=E5=AD=97=E7=AC=A6=E4=B8=B2=E4=B8=AD=E7=9A=84=E5=8D=95?= =?UTF-8?q?=E8=AF=8D=20=E6=8E=92=E7=89=88=E6=A0=BC=E5=BC=8F=E4=BF=AE?= =?UTF-8?q?=E5=A4=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- problems/0151.翻转字符串里的单词.md | 29 ++++++++++++++++------------- 1 file changed, 16 insertions(+), 13 deletions(-) diff --git a/problems/0151.翻转字符串里的单词.md b/problems/0151.翻转字符串里的单词.md index 6dd3cd49..19ccb725 100644 --- a/problems/0151.翻转字符串里的单词.md +++ b/problems/0151.翻转字符串里的单词.md @@ -28,10 +28,11 @@ 输出: "example good a" 解释: 如果两个单词间有多余的空格,将反转后单词间的空格减少到只含一个。 +## 算法公开课 -# 思路 +**[《代码随想录》算法视频公开课](https://programmercarl.com/other/gongkaike.html):[字符串复杂操作拿捏了! | LeetCode:151.翻转字符串里的单词](https://www.bilibili.com/video/BV1uT41177fX),相信结合视频再看本篇题解,更有助于大家对本题的理解**。 -针对本题,我录制了视频讲解:[字符串复杂操作拿捏了! | LeetCode:151.翻转字符串里的单词](https://www.bilibili.com/video/BV1uT41177fX),结合本题解一起看,事半功倍! +## 思路 **这道题目可以说是综合考察了字符串的多种操作。** @@ -204,8 +205,7 @@ public: ## 其他语言版本 - -Java: +### Java: ```Java class Solution { @@ -433,9 +433,10 @@ class Solution { } ``` -python: +### python: (版本一)先删除空白,然后整个反转,最后单词反转。 **因为字符串是不可变类型,所以反转单词的时候,需要将其转换成列表,然后通过join函数再将其转换成列表,所以空间复杂度不是O(1)** + ```Python class Solution: def reverseWords(self, s: str) -> str: @@ -467,7 +468,7 @@ class Solution: return " ".join(words) ``` -Go: +### Go: 版本一: @@ -571,7 +572,8 @@ func reverse(b *[]byte, left, right int) { -javaScript: +### JavaScript: + ```js /** * @param {string} s @@ -630,7 +632,7 @@ function reverse(strArr, start, end) { } ``` -TypeScript: +### TypeScript: ```typescript function reverseWords(s: string): string { @@ -689,7 +691,7 @@ function reverseWords(s: string): string { }; ``` -Swift: +### Swift: ```swift func reverseWords(_ s: String) -> String { @@ -766,7 +768,7 @@ func reverseWord(_ s: inout [Character]) { } ``` -Scala: +### Scala: ```scala object Solution { @@ -824,8 +826,8 @@ object Solution { } ``` +### PHP: -PHP: ```php function reverseWords($s) { $this->removeExtraSpaces($s); @@ -872,7 +874,7 @@ function reverseString(&$s, $start, $end) { return ; } ``` -Rust: +### Rust: ```Rust // 根据C++版本二思路进行实现 @@ -924,7 +926,7 @@ pub fn remove_extra_spaces(s: &mut Vec) { } } ``` -C: +### C: ```C // 翻转字符串中指定范围的字符 @@ -972,3 +974,4 @@ char * reverseWords(char * s){ + From 370a4d1c05b1204c652c00bcb90702947df11795 Mon Sep 17 00:00:00 2001 From: jinbudaily <18336218010@163.com> Date: Wed, 19 Jul 2023 15:50:44 +0800 Subject: [PATCH 057/122] =?UTF-8?q?=E6=9B=B4=E6=96=B0=20=E5=89=91=E6=8C=87?= =?UTF-8?q?Offer58-II.=E5=B7=A6=E6=97=8B=E8=BD=AC=E5=AD=97=E7=AC=A6?= =?UTF-8?q?=E4=B8=B2=20=E6=8E=92=E7=89=88=E6=A0=BC=E5=BC=8F=E4=BF=AE?= =?UTF-8?q?=E5=A4=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- problems/剑指Offer58-II.左旋转字符串.md | 26 ++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/problems/剑指Offer58-II.左旋转字符串.md b/problems/剑指Offer58-II.左旋转字符串.md index 6cd88456..008b7915 100644 --- a/problems/剑指Offer58-II.左旋转字符串.md +++ b/problems/剑指Offer58-II.左旋转字符串.md @@ -24,7 +24,7 @@ 限制: 1 <= k < s.length <= 10000 -# 思路 +## 思路 为了让本题更有意义,提升一下本题难度:**不能申请额外空间,只能在本串上操作**。 @@ -71,7 +71,7 @@ public: 是不是发现这代码也太简单了,哈哈。 -# 总结 +## 总结 此时我们已经反转好多次字符串了,来一起回顾一下吧。 @@ -86,7 +86,7 @@ public: 好了,反转字符串一共就介绍到这里,相信大家此时对反转字符串的常见操作已经很了解了。 -# 题外话 +## 题外话 一些同学热衷于使用substr,来做这道题。 其实使用substr 和 反转 时间复杂度是一样的 ,都是O(n),但是使用substr申请了额外空间,所以空间复杂度是O(n),而反转方法的空间复杂度是O(1)。 @@ -96,7 +96,8 @@ public: ## 其他语言版本 -Java: +### Java: + ```java class Solution { public String reverseLeftWords(String s, int n) { @@ -141,7 +142,7 @@ class Solution { } ``` -python: +### python: (版本一)使用切片 ```python @@ -211,7 +212,7 @@ class Solution: ``` -Go: +### Go: ```go func reverseLeftWords(s string, n int) string { @@ -234,8 +235,7 @@ func reverse(b []byte, left, right int){ } ``` - -JavaScript: +### JavaScript: ```javascript var reverseLeftWords = function(s, n) { @@ -279,7 +279,7 @@ var reverseLeftWords = function (s, n) { }; ``` -TypeScript: +### TypeScript: ```typescript function reverseLeftWords(s: string, n: number): string { @@ -311,7 +311,7 @@ function reverseLeftWords(s: string, n: number): string { }; ``` -Swift: +### Swift: ```swift func reverseLeftWords(_ s: String, _ n: Int) -> String { @@ -358,8 +358,7 @@ function reverse(&$s, $start, $end) { } ``` - -Scala: +### Scala: ```scala object Solution { @@ -388,7 +387,7 @@ object Solution { } ``` -Rust: +### Rust: ```Rust impl Solution { @@ -419,3 +418,4 @@ impl Solution { + From 5acebcc6f70f37d675f03356ecfc2f8f43b5949b Mon Sep 17 00:00:00 2001 From: jinbudaily <18336218010@163.com> Date: Wed, 19 Jul 2023 16:00:41 +0800 Subject: [PATCH 058/122] =?UTF-8?q?=E6=9B=B4=E6=96=B0=200028.=E5=AE=9E?= =?UTF-8?q?=E7=8E=B0strStr=20=E6=8E=92=E7=89=88=E6=A0=BC=E5=BC=8F=E4=BF=AE?= =?UTF-8?q?=E5=A4=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- problems/0028.实现strStr.md | 51 ++++++++++++++++++------------------- 1 file changed, 25 insertions(+), 26 deletions(-) diff --git a/problems/0028.实现strStr.md b/problems/0028.实现strStr.md index ac984d1a..53b57fd5 100644 --- a/problems/0028.实现strStr.md +++ b/problems/0028.实现strStr.md @@ -28,7 +28,7 @@ 对于本题而言,当 needle 是空字符串时我们应当返回 0 。这与C语言的 strstr() 以及 Java的 indexOf() 定义相符。 -# 思路 +## 思路 本题是KMP 经典题目。 @@ -60,13 +60,13 @@ KMP的经典思想就是:**当出现字符串不匹配时,可以记录一部 读完本篇可以顺便把leetcode上28.实现strStr()题目做了。 -# 什么是KMP +### 什么是KMP 说到KMP,先说一下KMP这个名字是怎么来的,为什么叫做KMP呢。 因为是由这三位学者发明的:Knuth,Morris和Pratt,所以取了三位学者名字的首字母。所以叫做KMP -# KMP有什么用 +### KMP有什么用 KMP主要应用在字符串匹配上。 @@ -84,7 +84,7 @@ KMP的主要思想是**当出现字符串不匹配时,可以知道一部分之 下面Carl就带大家把KMP的精髓,next数组弄清楚。 -# 什么是前缀表 +### 什么是前缀表 写过KMP的同学,一定都写过next数组,那么这个next数组究竟是个啥呢? @@ -122,7 +122,7 @@ next数组就是一个前缀表(prefix table)。 那么什么是前缀表:**记录下标i之前(包括i)的字符串中,有多大长度的相同前缀后缀。** -# 最长公共前后缀? +### 最长公共前后缀 文章中字符串的**前缀是指不包含最后一个字符的所有以第一个字符开头的连续子串**。 @@ -144,7 +144,7 @@ next数组就是一个前缀表(prefix table)。 等等.....。 -# 为什么一定要用前缀表 +### 为什么一定要用前缀表 这就是前缀表,那为啥就能告诉我们 上次匹配的位置,并跳过去呢? @@ -163,7 +163,7 @@ next数组就是一个前缀表(prefix table)。 **很多介绍KMP的文章或者视频并没有把为什么要用前缀表?这个问题说清楚,而是直接默认使用前缀表。** -# 如何计算前缀表 +### 如何计算前缀表 接下来就要说一说怎么计算前缀表。 @@ -205,7 +205,7 @@ next数组就是一个前缀表(prefix table)。 最后就在文本串中找到了和模式串匹配的子串了。 -# 前缀表与next数组 +### 前缀表与next数组 很多KMP算法的时间都是使用next数组来做回退操作,那么next数组与前缀表有什么关系呢? @@ -217,7 +217,7 @@ next数组就可以是前缀表,但是很多实现都是把前缀表统一减 后面我会提供两种不同的实现代码,大家就明白了。 -# 使用next数组来匹配 +### 使用next数组来匹配 **以下我们以前缀表统一减一之后的next数组来做演示**。 @@ -229,7 +229,7 @@ next数组就可以是前缀表,但是很多实现都是把前缀表统一减 ![KMP精讲4](https://code-thinking.cdn.bcebos.com/gifs/KMP%E7%B2%BE%E8%AE%B24.gif) -# 时间复杂度分析 +### 时间复杂度分析 其中n为文本串长度,m为模式串长度,因为在匹配的过程中,根据前缀表不断调整匹配的位置,可以看出匹配的过程是O(n),之前还要单独生成next数组,时间复杂度是O(m)。所以整个KMP算法的时间复杂度是O(n+m)的。 @@ -239,7 +239,7 @@ next数组就可以是前缀表,但是很多实现都是把前缀表统一减 都知道使用KMP算法,一定要构造next数组。 -# 构造next数组 +### 构造next数组 我们定义一个函数getNext来构建next数组,函数参数为指向next数组的指针,和一个字符串。 代码如下: @@ -338,7 +338,7 @@ void getNext(int* next, const string& s){ 得到了next数组之后,就要用这个来做匹配了。 -# 使用next数组来做匹配 +### 使用next数组来做匹配 在文本串s里 找是否出现过模式串t。 @@ -403,7 +403,7 @@ for (int i = 0; i < s.size(); i++) { // 注意i就从0开始 此时所有逻辑的代码都已经写出来了,力扣 28.实现strStr 题目的整体代码如下: -# 前缀表统一减一 C++代码实现 +### 前缀表统一减一 C++代码实现 ```CPP class Solution { @@ -447,7 +447,7 @@ public: * 时间复杂度: O(n + m) * 空间复杂度: O(m), 只需要保存字符串needle的前缀表 -# 前缀表(不减一)C++实现 +### 前缀表(不减一)C++实现 那么前缀表就不减一了,也不右移的,到底行不行呢? @@ -546,7 +546,7 @@ public: * 空间复杂度: O(m) -# 总结 +## 总结 我们介绍了什么是KMP,KMP可以解决什么问题,然后分析KMP算法里的next数组,知道了next数组就是前缀表,再分析为什么要是前缀表而不是什么其他表。 @@ -563,8 +563,7 @@ public: ## 其他语言版本 - -Java: +### Java: ```Java class Solution { @@ -691,8 +690,9 @@ class Solution { } ``` -Python3: +### Python3: (版本一)前缀表(减一) + ```python class Solution: def getNext(self, next, s): @@ -781,9 +781,9 @@ class Solution: def strStr(self, haystack: str, needle: str) -> int: return haystack.find(needle) -``` +``` -Go: +### Go: ```go // 方法一:前缀表使用减1实现 @@ -871,7 +871,7 @@ func strStr(haystack string, needle string) int { } ``` -JavaScript版本 +### JavaScript: > 前缀表统一减一 @@ -959,7 +959,7 @@ var strStr = function (haystack, needle) { }; ``` -TypeScript版本: +### TypeScript: > 前缀表统一减一 @@ -1036,7 +1036,7 @@ function strStr(haystack: string, needle: string): number { } ``` -Swift 版本 +### Swift: > 前缀表统一减一 @@ -1196,7 +1196,7 @@ func strStr(_ haystack: String, _ needle: String) -> Int { ``` -PHP: +### PHP: > 前缀表统一减一 ```php @@ -1272,7 +1272,7 @@ function getNext(&$next, $s){ } ``` -Rust: +### Rust: > 前缀表统一不减一 ```Rust @@ -1362,4 +1362,3 @@ impl Solution { - From 202dd382d29eb34f311d5f35f001255b2b770402 Mon Sep 17 00:00:00 2001 From: jinbudaily <18336218010@163.com> Date: Wed, 19 Jul 2023 16:06:12 +0800 Subject: [PATCH 059/122] =?UTF-8?q?=E6=9B=B4=E6=96=B0=200459.=E9=87=8D?= =?UTF-8?q?=E5=A4=8D=E7=9A=84=E5=AD=97=E7=AC=A6=E4=B8=B2=20=E6=8E=92?= =?UTF-8?q?=E7=89=88=E6=A0=BC=E5=BC=8F=E4=BF=AE=E5=A4=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- problems/0459.重复的子字符串.md | 35 +++++++++++++++------------------ 1 file changed, 16 insertions(+), 19 deletions(-) diff --git a/problems/0459.重复的子字符串.md b/problems/0459.重复的子字符串.md index e26d04ad..f99102ab 100644 --- a/problems/0459.重复的子字符串.md +++ b/problems/0459.重复的子字符串.md @@ -5,8 +5,6 @@

参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!

- - > KMP算法还能干这个 # 459.重复的子字符串 @@ -29,9 +27,11 @@ * 输出: True * 解释: 可由子字符串 "abc" 重复四次构成。 (或者子字符串 "abcabc" 重复两次构成。) -# 思路 +## 算法公开课 -针对本题,我录制了视频讲解:[字符串这么玩,可有点难度! | LeetCode:459.重复的子字符串](https://www.bilibili.com/video/BV1cg41127fw),结合本题解一起看,事半功倍! +**[《代码随想录》算法视频公开课](https://programmercarl.com/other/gongkaike.html):[字符串这么玩,可有点难度! | LeetCode:459.重复的子字符串](https://www.bilibili.com/video/BV1cg41127fw),相信结合视频再看本篇题解,更有助于大家对本题的理解**。 + +## 思路 暴力的解法, 就是一个for循环获取 子串的终止位置, 然后判断子串是否能重复构成字符串,又嵌套一个for循环,所以是O(n^2)的时间复杂度。 @@ -44,7 +44,7 @@ 主要讲一讲移动匹配 和 KMP两种方法。 -## 移动匹配 +### 移动匹配 当一个字符串s:abcabc,内部由重复的子串组成,那么这个字符串的结构一定是这样的: @@ -80,9 +80,9 @@ public: 如果我们做过 [28.实现strStr](https://programmercarl.com/0028.实现strStr.html) 题目的话,其实就知道,**实现一个 高效的算法来判断 一个字符串中是否出现另一个字符串是很复杂的**,这里就涉及到了KMP算法。 -## KMP +### KMP -### 为什么会使用KMP +#### 为什么会使用KMP 以下使用KMP方式讲解,强烈建议大家先把以下两个视频看了,理解KMP算法,再来看下面讲解,否则会很懵。 * [视频讲解版:帮你把KMP算法学个通透!(理论篇)](https://www.bilibili.com/video/BV1PD4y1o7nd/) @@ -105,7 +105,7 @@ KMP算法中next数组为什么遇到字符不匹配的时候可以找到上一 ![图三](https://code-thinking-1253855093.file.myqcloud.com/pics/20220728205249.png) -### 如何找到最小重复子串 +#### 如何找到最小重复子串 这里有同学就问了,为啥一定是开头的ab呢。 其实最关键还是要理解 最长相等前后缀,如图: @@ -123,7 +123,7 @@ KMP算法中next数组为什么遇到字符不匹配的时候可以找到上一 正是因为 最长相等前后缀的规则,当一个字符串由重复子串组成的,最长相等前后缀不包含的子串就是最小重复子串。 -### 简单推理 +#### 简单推理 这里再给出一个数学推导,就容易理解很多。 @@ -229,7 +229,7 @@ public: ## 其他语言版本 -Java: +### Java: ```java class Solution { @@ -261,8 +261,7 @@ class Solution { } ``` - -Python: +### Python: (版本一) 前缀表 减一 ```python @@ -346,8 +345,7 @@ class Solution: return False ``` - -Go: +### Go: 这里使用了前缀表统一减一的实现方式 @@ -405,7 +403,7 @@ func repeatedSubstringPattern(s string) bool { } ``` -JavaScript版本 +### JavaScript: > 前缀表统一减一 @@ -479,7 +477,7 @@ var repeatedSubstringPattern = function (s) { }; ``` -TypeScript: +### TypeScript: > 前缀表统一减一 @@ -539,8 +537,7 @@ function repeatedSubstringPattern(s: string): boolean { }; ``` - -Swift: +### Swift: > 前缀表统一减一 ```swift @@ -623,7 +620,7 @@ Swift: } ``` -Rust: +### Rust: >前缀表统一不减一 ```Rust From 4fe1f08acd1a7fe4a6af2ea4920ca97a284ce0c4 Mon Sep 17 00:00:00 2001 From: jinbudaily <18336218010@163.com> Date: Wed, 19 Jul 2023 16:09:03 +0800 Subject: [PATCH 060/122] =?UTF-8?q?=E6=9B=B4=E6=96=B0=20=E5=AD=97=E7=AC=A6?= =?UTF-8?q?=E4=B8=B2=E6=80=BB=E7=BB=93=20=E6=8E=92=E7=89=88=E6=A0=BC?= =?UTF-8?q?=E5=BC=8F=E4=BF=AE=E5=A4=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- problems/字符串总结.md | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/problems/字符串总结.md b/problems/字符串总结.md index c12d1764..5c2f0164 100644 --- a/problems/字符串总结.md +++ b/problems/字符串总结.md @@ -11,7 +11,7 @@ 那么这次我们来做一个总结。 -# 什么是字符串 +## 什么是字符串 字符串是若干字符组成的有限序列,也可以理解为是一个字符数组,但是很多语言对字符串做了特殊的规定,接下来我来说一说C/C++中的字符串。 @@ -42,7 +42,7 @@ for (int i = 0; i < a.size(); i++) { 所以想处理字符串,我们还是会定义一个string类型。 -# 要不要使用库函数 +## 要不要使用库函数 在文章[344.反转字符串](https://programmercarl.com/0344.反转字符串.html)中强调了**打基础的时候,不要太迷恋于库函数。** @@ -52,7 +52,7 @@ for (int i = 0; i < a.size(); i++) { **如果库函数仅仅是 解题过程中的一小部分,并且你已经很清楚这个库函数的内部实现原理的话,可以考虑使用库函数。** -# 双指针法 +## 双指针法 在[344.反转字符串](https://programmercarl.com/0344.反转字符串.html) ,我们使用双指针法实现了反转字符串的操作,**双指针法在数组,链表和字符串中很常用。** @@ -67,7 +67,7 @@ for (int i = 0; i < a.size(); i++) { 一些同学会使用for循环里调用库函数erase来移除元素,这其实是O(n^2)的操作,因为erase就是O(n)的操作,所以这也是典型的不知道库函数的时间复杂度,上来就用的案例了。 -# 反转系列 +## 反转系列 在反转上还可以在加一些玩法,其实考察的是对代码的掌控能力。 @@ -87,7 +87,7 @@ for (int i = 0; i < a.size(); i++) { 在[字符串:反转个字符串还有这个用处?](https://programmercarl.com/剑指Offer58-II.左旋转字符串.html)中,我们通过**先局部反转再整体反转**达到了左旋的效果。 -# KMP +## KMP KMP的主要思想是**当出现字符串不匹配时,可以知道一部分之前已经匹配的文本内容,可以利用这些信息避免从头再去做匹配了。** @@ -110,7 +110,7 @@ KMP的精髓所在就是前缀表,在[KMP精讲](https://programmercarl.com/00 其中主要**理解j=next[x]这一步最为关键!** -# 总结 +## 总结 字符串类类型的题目,往往想法比较简单,但是实现起来并不容易,复杂的字符串题目非常考验对代码的掌控能力。 @@ -128,3 +128,4 @@ KMP算法是字符串查找最重要的算法,但彻底理解KMP并不容易 + From c3ebc91d4db0fc5b86945b910babd8c4ad2328b2 Mon Sep 17 00:00:00 2001 From: jinbudaily <18336218010@163.com> Date: Thu, 20 Jul 2023 14:27:16 +0800 Subject: [PATCH 061/122] =?UTF-8?q?=E6=9B=B4=E6=96=B0=20=E5=8F=8C=E6=8C=87?= =?UTF-8?q?=E9=92=88=E6=80=BB=E7=BB=93=20=E6=8E=92=E7=89=88=E6=A0=BC?= =?UTF-8?q?=E5=BC=8F=E4=BF=AE=E5=A4=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- problems/双指针总结.md | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/problems/双指针总结.md b/problems/双指针总结.md index 04a8cb9a..6621e039 100644 --- a/problems/双指针总结.md +++ b/problems/双指针总结.md @@ -8,7 +8,8 @@ 相信大家已经对双指针法很熟悉了,但是双指针法并不隶属于某一种数据结构,我们在讲解数组,链表,字符串都用到了双指针法,所有有必要针对双指针法做一个总结。 -# 数组篇 +# 双指针总结篇 +## 数组篇 在[数组:就移除个元素很难么?](https://programmercarl.com/0027.移除元素.html)中,原地移除数组上的元素,我们说到了数组上的元素,不能真正的删除,只能覆盖。 @@ -26,7 +27,7 @@ for (int i = 0; i < array.size(); i++) { 所以此时使用双指针法才展现出效率的优势:**通过两个指针在一个for循环下完成两个for循环的工作。** -# 字符串篇 +## 字符串篇 在[字符串:这道题目,使用库函数一行代码搞定](https://programmercarl.com/0344.反转字符串.html)中讲解了反转字符串,注意这里强调要原地反转,要不然就失去了题目的意义。 @@ -48,7 +49,7 @@ for (int i = 0; i < array.size(); i++) { **主要还是大家用erase用的比较随意,一定要注意for循环下用erase的情况,一般可以用双指针写效率更高!** -# 链表篇 +## 链表篇 翻转链表是现场面试,白纸写代码的好题,考察了候选者对链表以及指针的熟悉程度,而且代码也不长,适合在白纸上写。 @@ -62,7 +63,7 @@ for (int i = 0; i < array.size(); i++) { 那么找到环的入口,其实需要点简单的数学推理,我在文章中把找环的入口清清楚楚的推理的一遍,如果对找环入口不够清楚的同学建议自己看一看[链表:环找到了,那入口呢?](https://programmercarl.com/0142.环形链表II.html)。 -# N数之和篇 +## N数之和篇 在[哈希表:解决了两数之和,那么能解决三数之和么?](https://programmercarl.com/0015.三数之和.html)中,讲到使用哈希法可以解决1.两数之和的问题 @@ -87,7 +88,7 @@ for (int i = 0; i < array.size(); i++) { 同样的道理,五数之和,n数之和都是在这个基础上累加。 -# 总结 +## 总结 本文中一共介绍了leetcode上九道使用双指针解决问题的经典题目,除了链表一些题目一定要使用双指针,其他题目都是使用双指针来提高效率,一般是将O(n^2)的时间复杂度,降为$O(n)$。 From de770c60e5ae781a9e65071e03ba4876237ed6fb Mon Sep 17 00:00:00 2001 From: jinbudaily <18336218010@163.com> Date: Thu, 20 Jul 2023 14:36:04 +0800 Subject: [PATCH 062/122] =?UTF-8?q?=E6=9B=B4=E6=96=B0=20=E6=A0=88=E4=B8=8E?= =?UTF-8?q?=E9=98=9F=E5=88=97=E7=90=86=E8=AE=BA=E5=9F=BA=E7=A1=80=20?= =?UTF-8?q?=E6=8E=92=E7=89=88=E6=A0=BC=E5=BC=8F=E4=BF=AE=E5=A4=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- problems/栈与队列理论基础.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/problems/栈与队列理论基础.md b/problems/栈与队列理论基础.md index 0075deb6..ad748e48 100644 --- a/problems/栈与队列理论基础.md +++ b/problems/栈与队列理论基础.md @@ -4,8 +4,11 @@

参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!

+ > 来看看栈和队列不为人知的一面 +# 栈与队列理论基础 + 我想栈和队列的原理大家应该很熟悉了,队列是先进先出,栈是先进后出。 如图所示: @@ -93,3 +96,4 @@ std::queue> third; // 定义以list为底层容器的队列 + From 4b5e198b170bade71d565d8ba3f7e29543f3bbef Mon Sep 17 00:00:00 2001 From: jinbudaily <18336218010@163.com> Date: Thu, 20 Jul 2023 14:40:33 +0800 Subject: [PATCH 063/122] =?UTF-8?q?=E6=9B=B4=E6=96=B0=200232.=E7=94=A8?= =?UTF-8?q?=E6=A0=88=E5=AE=9E=E7=8E=B0=E9=98=9F=E5=88=97=20=E6=8E=92?= =?UTF-8?q?=E7=89=88=E6=A0=BC=E5=BC=8F=E4=BF=AE=E5=A4=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- problems/0232.用栈实现队列.md | 33 ++++++++++++++++++--------------- 1 file changed, 18 insertions(+), 15 deletions(-) diff --git a/problems/0232.用栈实现队列.md b/problems/0232.用栈实现队列.md index 4a57ee96..c510fc12 100644 --- a/problems/0232.用栈实现队列.md +++ b/problems/0232.用栈实现队列.md @@ -36,11 +36,12 @@ queue.empty(); // 返回 false * 你所使用的语言也许不支持栈。你可以使用 list 或者 deque(双端队列)来模拟一个栈,只要是标准的栈操作即可。 * 假设所有操作都是有效的 (例如,一个空的队列不会调用 pop 或者 peek 操作)。 +## 算法公开课 + +**[《代码随想录》算法视频公开课](https://programmercarl.com/other/gongkaike.html):[栈的基本操作! | LeetCode:232.用栈实现队列](https://www.bilibili.com/video/BV1nY4y1w7VC),相信结合视频再看本篇题解,更有助于大家对本题的理解**。 + ## 思路 -《代码随想录》算法公开课:[栈的基本操作! | LeetCode:232.用栈实现队列](https://www.bilibili.com/video/BV1nY4y1w7VC),相信结合视频再看本篇题解,更有助于大家对栈和队列的理解。 - - 这是一道模拟题,不涉及到具体算法,考察的就是对栈和队列的掌握程度。 使用栈来模式队列的行为,如果仅仅用一个栈,是一定不行的,所以需要两个栈**一个输入栈,一个输出栈**,这里要注意输入栈和输出栈的关系。 @@ -132,7 +133,7 @@ public: ## 其他语言版本 -Java: +### Java: ```java class MyQueue { @@ -179,8 +180,8 @@ class MyQueue { ``` +### Python: -Python: ```python class MyQueue: @@ -231,8 +232,8 @@ class MyQueue: ``` +### Go: -Go: ```Go type MyQueue struct { stackIn []int //输入栈 @@ -283,7 +284,7 @@ func (this *MyQueue) Empty() bool { } ``` - javaScript: +### JavaScript: ```js // 使用两个数组的栈方法(push, pop) 实现队列 @@ -338,7 +339,7 @@ MyQueue.prototype.empty = function() { }; ``` -TypeScript: +### TypeScript: ```typescript class MyQueue { @@ -374,7 +375,7 @@ class MyQueue { } ``` -Swift: +### Swift: ```swift class MyQueue { @@ -413,7 +414,8 @@ class MyQueue { } ``` -C: +### C: + ```C /* 1.两个type为int的数组(栈),大小为100 @@ -490,8 +492,8 @@ void myQueueFree(MyQueue* obj) { } ``` +### C#: -C#: ```csharp public class MyQueue { Stack inStack; @@ -534,7 +536,8 @@ public class MyQueue { -PHP: +### PHP: + ```php // SplStack 类通过使用一个双向链表来提供栈的主要功能。[PHP 5 >= 5.3.0, PHP 7, PHP 8] // https://www.php.net/manual/zh/class.splstack.php @@ -579,7 +582,8 @@ class MyQueue { } ``` -Scala: +### Scala: + ```scala class MyQueue() { import scala.collection.mutable @@ -621,7 +625,7 @@ class MyQueue() { } ``` -rust: +### Rust: ```rust struct MyQueue { @@ -666,4 +670,3 @@ impl MyQueue { - From c18dbf059544b7bd100ff101cc92a2ee241434e5 Mon Sep 17 00:00:00 2001 From: jinbudaily <18336218010@163.com> Date: Thu, 20 Jul 2023 14:45:24 +0800 Subject: [PATCH 064/122] =?UTF-8?q?=E6=9B=B4=E6=96=B0=200225.=E7=94=A8?= =?UTF-8?q?=E9=98=9F=E5=88=97=E5=AE=9E=E7=8E=B0=E6=A0=88=20=E6=8E=92?= =?UTF-8?q?=E7=89=88=E6=A0=BC=E5=BC=8F=E4=BF=AE=E5=A4=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- problems/0225.用队列实现栈.md | 37 ++++++++++++++++++----------------- 1 file changed, 19 insertions(+), 18 deletions(-) diff --git a/problems/0225.用队列实现栈.md b/problems/0225.用队列实现栈.md index 94c79404..13b742f8 100644 --- a/problems/0225.用队列实现栈.md +++ b/problems/0225.用队列实现栈.md @@ -25,11 +25,11 @@ * 你所使用的语言也许不支持队列。 你可以使用 list 或者 deque(双端队列)来模拟一个队列 , 只要是标准的队列操作即可。 * 你可以假设所有操作都是有效的(例如, 对一个空的栈不会调用 pop 或者 top 操作)。 +## 算法公开课 -# 思路 +**[《代码随想录》算法视频公开课](https://programmercarl.com/other/gongkaike.html):[队列的基本操作! | LeetCode:225. 用队列实现栈](https://www.bilibili.com/video/BV1Fd4y1K7sm),相信结合视频再看本篇题解,更有助于大家对本题的理解**。 - -《代码随想录》算法公开课:[队列的基本操作! | LeetCode:225. 用队列实现栈](https://www.bilibili.com/video/BV1Fd4y1K7sm),相信结合视频再看本篇题解,更有助于大家对链表的理解。 +## 思路 (这里要强调是单向队列) @@ -114,7 +114,7 @@ public: * 时间复杂度: push为O(n),其他为O(1) * 空间复杂度: O(n) -# 优化 +## 优化 其实这道题目就是用一个队列就够了。 @@ -162,9 +162,9 @@ public: * 空间复杂度: O(n) -# 其他语言版本 +## 其他语言版本 -Java: +### Java: 使用两个 Queue 实现方法1 ```java @@ -404,7 +404,7 @@ class MyStack { } ``` -Python: +### Python: ```python from collections import deque @@ -496,8 +496,7 @@ class MyStack: return not self.que ``` - -Go: +### Go: 使用两个队列实现 ```go @@ -628,9 +627,7 @@ func (this *MyStack) Empty() bool { */ ``` - - -javaScript: +### JavaScript: 使用数组(push, shift)模拟队列 @@ -740,7 +737,7 @@ MyStack.prototype.empty = function() { ``` -TypeScript: +### TypeScript: 版本一:使用两个队列模拟栈 @@ -812,7 +809,7 @@ class MyStack { } ``` -Swift +### Swift: ```Swift // 定义一个队列数据结构 @@ -931,8 +928,9 @@ class MyStack { } } ``` -Scala: +### Scala: 使用两个队列模拟栈: + ```scala import scala.collection.mutable @@ -1015,8 +1013,8 @@ class MyStack() { } ``` +### C#: -C#: ```csharp public class MyStack { Queue queue1; @@ -1051,8 +1049,9 @@ public class MyStack { } ``` -PHP -> 双对列 +### PHP: + +> 双队列 ```php // SplQueue 类通过使用一个双向链表来提供队列的主要功能。(PHP 5 >= 5.3.0, PHP 7, PHP 8) // https://www.php.net/manual/zh/class.splqueue.php @@ -1130,6 +1129,8 @@ class MyStack { } ``` +### Rust: + > rust:单队列 ```rust From a1ef2d03f64f6884fade8bfe5d2ed9dbceb129d8 Mon Sep 17 00:00:00 2001 From: jinbudaily <18336218010@163.com> Date: Thu, 20 Jul 2023 14:49:03 +0800 Subject: [PATCH 065/122] =?UTF-8?q?=E6=9B=B4=E6=96=B0=20020.=E6=9C=89?= =?UTF-8?q?=E6=95=88=E7=9A=84=E6=8B=AC=E5=8F=B7=20=E6=8E=92=E7=89=88?= =?UTF-8?q?=E6=A0=BC=E5=BC=8F=E4=BF=AE=E5=A4=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- problems/0020.有效的括号.md | 39 ++++++++++++++++++++++--------------- 1 file changed, 23 insertions(+), 16 deletions(-) diff --git a/problems/0020.有效的括号.md b/problems/0020.有效的括号.md index 213d61b7..045c79ee 100644 --- a/problems/0020.有效的括号.md +++ b/problems/0020.有效的括号.md @@ -39,12 +39,13 @@ * 输入: "{[]}" * 输出: true -# 思路 +## 算法公开课 -《代码随想录》算法视频公开课:[栈的拿手好戏!| LeetCode:20. 有效的括号](https://www.bilibili.com/video/BV1AF411w78g),相信结合视频在看本篇题解,更有助于大家对链表的理解。 +**[《代码随想录》算法视频公开课](https://programmercarl.com/other/gongkaike.html):[栈的拿手好戏!| LeetCode:20. 有效的括号](https://www.bilibili.com/video/BV1AF411w78g),相信结合视频再看本篇题解,更有助于大家对本题的理解**。 +## 思路 -## 题外话 +### 题外话 **括号匹配是使用栈解决的经典问题。** @@ -68,7 +69,7 @@ cd a/b/c/../../ 这里我就不过多展开了,先来看题。 -## 进入正题 +### 进入正题 由于栈结构的特殊性,非常适合做对称匹配类的题目。 @@ -143,8 +144,8 @@ public: ## 其他语言版本 +### Java: -Java: ```Java class Solution { public boolean isValid(String s) { @@ -171,7 +172,8 @@ class Solution { } ``` -Python: +### Python: + ```python # 方法一,仅使用栈,更省空间 class Solution: @@ -213,7 +215,8 @@ class Solution: return True if not stack else False ``` -Go: +### Go: + ```Go func isValid(s string) bool { hash := map[byte]byte{')':'(', ']':'[', '}':'{'} @@ -235,7 +238,8 @@ func isValid(s string) bool { } ``` -Ruby: +### Ruby: + ```ruby def is_valid(strs) symbol_map = {')' => '(', '}' => '{', ']' => '['} @@ -253,7 +257,8 @@ def is_valid(strs) end ``` -Javascript: +### Javascript: + ```javascript var isValid = function (s) { const stack = []; @@ -296,7 +301,7 @@ var isValid = function(s) { }; ``` -TypeScript: +### TypeScript: 版本一:普通版 @@ -348,7 +353,7 @@ function isValid(s: string): boolean { }; ``` -Swift +### Swift: ```swift func isValid(_ s: String) -> Bool { @@ -373,7 +378,8 @@ func isValid(_ s: String) -> Bool { } ``` -C: +### C: + ```C //辅助函数:判断栈顶元素与输入的括号是否为一对。若不是,则返回False int notMatch(char par, char* stack, int stackTop) { @@ -414,8 +420,8 @@ bool isValid(char * s){ } ``` +### C#: -C#: ```csharp public class Solution { public bool IsValid(string s) { @@ -447,7 +453,8 @@ public class Solution { } ``` -PHP: +### PHP: + ```php // https://www.php.net/manual/zh/class.splstack.php class Solution @@ -475,8 +482,8 @@ class Solution } ``` +### Scala: -Scala: ```scala object Solution { import scala.collection.mutable @@ -499,7 +506,7 @@ object Solution { } ``` -rust: +### Rust: ```rust impl Solution { From 70888c2b6074fa28f291108b4225735f6c24126f Mon Sep 17 00:00:00 2001 From: jinbudaily <18336218010@163.com> Date: Thu, 20 Jul 2023 14:53:33 +0800 Subject: [PATCH 066/122] =?UTF-8?q?=E6=9B=B4=E6=96=B0=201047.=E5=88=A0?= =?UTF-8?q?=E9=99=A4=E5=AD=97=E7=AC=A6=E4=B8=B2=E4=B8=AD=E7=9A=84=E6=89=80?= =?UTF-8?q?=E6=9C=89=E7=9B=B8=E9=82=BB=E9=87=8D=E5=A4=8D=E9=A1=B9=20?= =?UTF-8?q?=E6=8E=92=E7=89=88=E6=A0=BC=E5=BC=8F=E4=BF=AE=E5=A4=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- problems/1047.删除字符串中的所有相邻重复项.md | 37 ++++++++++--------- 1 file changed, 19 insertions(+), 18 deletions(-) diff --git a/problems/1047.删除字符串中的所有相邻重复项.md b/problems/1047.删除字符串中的所有相邻重复项.md index 486d198b..ad54f0f8 100644 --- a/problems/1047.删除字符串中的所有相邻重复项.md +++ b/problems/1047.删除字符串中的所有相邻重复项.md @@ -5,8 +5,6 @@

参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!

- - > 匹配问题都是栈的强项 # 1047. 删除字符串中的所有相邻重复项 @@ -30,11 +28,13 @@ * 1 <= S.length <= 20000 * S 仅由小写英文字母组成。 -# 思路 +## 算法公开课 -《代码随想录》算法视频公开课:[栈的好戏还要继续!| LeetCode:1047. 删除字符串中的所有相邻重复项](https://www.bilibili.com/video/BV12a411P7mw),相信结合视频在看本篇题解,更有助于大家对本题的理解。 +**[《代码随想录》算法视频公开课](https://programmercarl.com/other/gongkaike.html):[栈的好戏还要继续!| LeetCode:1047. 删除字符串中的所有相邻重复项](https://www.bilibili.com/video/BV12a411P7mw),相信结合视频再看本篇题解,更有助于大家对本题的理解**。 -## 正题 +## 思路 + +### 正题 本题要删除相邻相同元素,相对于[20. 有效的括号](https://programmercarl.com/0020.%E6%9C%89%E6%95%88%E7%9A%84%E6%8B%AC%E5%8F%B7.html)来说其实也是匹配问题,20. 有效的括号 是匹配左右括号,本题是匹配相邻元素,最后都是做消除的操作。 @@ -105,7 +105,7 @@ public: * 时间复杂度: O(n) * 空间复杂度: O(1),返回值不计空间复杂度 -## 题外话 +### 题外话 这道题目就像是我们玩过的游戏对对碰,如果相同的元素挨在一起就要消除。 @@ -125,8 +125,7 @@ public: ## 其他语言版本 - -Java: +### Java: 使用 Deque 作为堆栈 ```Java @@ -203,7 +202,8 @@ class Solution { } ``` -Python: +### Python: + ```python # 方法一,使用栈 class Solution: @@ -239,7 +239,7 @@ class Solution: return ''.join(res[0: slow]) ``` -Go: +### Go: ```go func removeDuplicates(s string) string { @@ -258,7 +258,7 @@ func removeDuplicates(s string) string { } ``` -javaScript: +### JavaScript: 法一:使用栈 @@ -295,7 +295,7 @@ var removeDuplicates = function(s) { }; ``` -TypeScript: +### TypeScript: ```typescript function removeDuplicates(s: string): string { @@ -318,7 +318,7 @@ function removeDuplicates(s: string): string { }; ``` -C: +### C: 方法一:使用栈 ```c @@ -371,7 +371,8 @@ char * removeDuplicates(char * s){ } ``` -Swift: +### Swift: + ```swift func removeDuplicates(_ s: String) -> String { var stack = [Character]() @@ -386,8 +387,8 @@ func removeDuplicates(_ s: String) -> String { } ``` +### C#: -C#: ```csharp public string RemoveDuplicates(string s) { //拿字符串直接作为栈,省去了栈还要转为字符串的操作 @@ -405,8 +406,8 @@ public string RemoveDuplicates(string s) { } ``` +### PHP: -PHP: ```php class Solution { function removeDuplicates($s) { @@ -431,8 +432,8 @@ class Solution { } ``` +### Scala: -Scala: ```scala object Solution { import scala.collection.mutable @@ -455,7 +456,7 @@ object Solution { } ``` -rust: +### Rust: ```rust impl Solution { From 7f4d74049ebc0d42930d5afe51b4c766295b0366 Mon Sep 17 00:00:00 2001 From: jinbudaily <18336218010@163.com> Date: Thu, 20 Jul 2023 14:57:59 +0800 Subject: [PATCH 067/122] =?UTF-8?q?=E6=9B=B4=E6=96=B0=200150.=E9=80=86?= =?UTF-8?q?=E6=B3=A2=E5=85=B0=E8=A1=A8=E8=BE=BE=E5=BC=8F=E6=B1=82=E5=80=BC?= =?UTF-8?q?=20=E6=8E=92=E7=89=88=E6=A0=BC=E5=BC=8F=E4=BF=AE=E5=A4=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- problems/0150.逆波兰表达式求值.md | 38 +++++++++++++++++-------------- 1 file changed, 21 insertions(+), 17 deletions(-) diff --git a/problems/0150.逆波兰表达式求值.md b/problems/0150.逆波兰表达式求值.md index 09cc4f96..663a68ea 100644 --- a/problems/0150.逆波兰表达式求值.md +++ b/problems/0150.逆波兰表达式求值.md @@ -5,8 +5,6 @@

参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!

- - > 这不仅仅是一道好题,也展现出计算机的思考方式 # 150. 逆波兰表达式求值 @@ -63,9 +61,13 @@ * 适合用栈操作运算:遇到数字则入栈;遇到运算符则取出栈顶两个数字进行计算,并将结果压入栈中。 -# 思路 +## 算法公开课 -《代码随想录》算法视频公开课:[栈的最后表演! | LeetCode:150. 逆波兰表达式求值](https://www.bilibili.com/video/BV1kd4y1o7on),相信结合视频再看本篇题解,更有助于大家对本题的理解。 +**[《代码随想录》算法视频公开课](https://programmercarl.com/other/gongkaike.html):[栈的最后表演! | LeetCode:150. 逆波兰表达式求值](https://www.bilibili.com/video/BV1kd4y1o7on),相信结合视频再看本篇题解,更有助于大家对本题的理解**。 + +## 思路 + +### 正题 在上一篇文章中[1047.删除字符串中的所有相邻重复项](https://programmercarl.com/1047.删除字符串中的所有相邻重复项.html)提到了 递归就是用栈来实现的。 @@ -117,7 +119,7 @@ public: * 空间复杂度: O(n) -## 题外话 +### 题外话 我们习惯看到的表达式都是中缀表达式,因为符合我们的习惯,但是中缀表达式对于计算机来说就不是很友好了。 @@ -134,11 +136,9 @@ public: > During the 1970s and 1980s, Hewlett-Packard used RPN in all of their desktop and hand-held calculators, and continued to use it in some models into the 2020s. - - ## 其他语言版本 -java: +### Java: ```Java class Solution { @@ -164,7 +164,7 @@ class Solution { } ``` -python3 +### Python3: ```python from operator import add, sub, mul @@ -201,7 +201,8 @@ class Solution: ``` -Go: +### Go: + ```Go func evalRPN(tokens []string) int { stack := []int{} @@ -228,7 +229,7 @@ func evalRPN(tokens []string) int { } ``` -javaScript: +### JavaScript: ```js var evalRPN = function (tokens) { @@ -259,7 +260,7 @@ var evalRPN = function (tokens) { }; ``` -TypeScript: +### TypeScript: 普通版: @@ -324,7 +325,8 @@ function evalRPN(tokens: string[]): number { }; ``` -Swift: +### Swift: + ```Swift func evalRPN(_ tokens: [String]) -> Int { var stack = [Int]() @@ -357,7 +359,8 @@ func evalRPN(_ tokens: [String]) -> Int { } ``` -C#: +### C#: + ```csharp public int EvalRPN(string[] tokens) { int num; @@ -391,8 +394,8 @@ public int EvalRPN(string[] tokens) { } ``` +### PHP: -PHP: ```php class Solution { function evalRPN($tokens) { @@ -417,7 +420,8 @@ class Solution { } ``` -Scala: +### Scala: + ```scala object Solution { import scala.collection.mutable @@ -447,7 +451,7 @@ object Solution { } ``` -rust: +### Rust: ```rust impl Solution { From 5a6bf6d85534e304e73460d67db006f5c1475657 Mon Sep 17 00:00:00 2001 From: jinbudaily <18336218010@163.com> Date: Thu, 20 Jul 2023 15:01:53 +0800 Subject: [PATCH 068/122] =?UTF-8?q?=E6=9B=B4=E6=96=B0=200239.=E6=BB=91?= =?UTF-8?q?=E5=8A=A8=E7=AA=97=E5=8F=A3=E6=9C=80=E5=A4=A7=E5=80=BC=20?= =?UTF-8?q?=E6=8E=92=E7=89=88=E6=A0=BC=E5=BC=8F=E4=BF=AE=E5=A4=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- problems/0239.滑动窗口最大值.md | 37 +++++++++++++++++++-------------- 1 file changed, 21 insertions(+), 16 deletions(-) diff --git a/problems/0239.滑动窗口最大值.md b/problems/0239.滑动窗口最大值.md index f1c4b76c..6f420479 100644 --- a/problems/0239.滑动窗口最大值.md +++ b/problems/0239.滑动窗口最大值.md @@ -28,11 +28,11 @@ * -10^4 <= nums[i] <= 10^4 * 1 <= k <= nums.length +## 算法公开课 +**[《代码随想录》算法视频公开课](https://programmercarl.com/other/gongkaike.html):[单调队列正式登场!| LeetCode:239. 滑动窗口最大值](https://www.bilibili.com/video/BV1XS4y1p7qj),相信结合视频再看本篇题解,更有助于大家对本题的理解**。 -# 思路 - -《代码随想录》算法视频公开课:[单调队列正式登场!| LeetCode:239. 滑动窗口最大值](https://www.bilibili.com/video/BV1XS4y1p7qj),相信结合视频在看本篇题解,更有助于大家对本题的理解。 +## 思路 这是使用单调队列的经典题目。 @@ -196,7 +196,7 @@ public: 空间复杂度因为我们定义一个辅助队列,所以是O(k)。 -# 扩展 +## 扩展 大家貌似对单调队列 都有一些疑惑,首先要明确的是,题解中单调队列里的pop和push接口,仅适用于本题哈。单调队列不是一成不变的,而是不同场景不同写法,总之要保证队列里单调递减或递增的原则,所以叫做单调队列。 不要以为本题中的单调队列实现就是固定的写法哈。 @@ -204,10 +204,10 @@ public: -# 其他语言版本 +## 其他语言版本 +### Java: -Java: ```Java //解法一 //自定义数组 @@ -298,7 +298,8 @@ class Solution { } ``` -Python: +### Python: + ```python from collections import deque @@ -338,8 +339,7 @@ class Solution: return result ``` - -Go: +### Go: ```go // 封装单调队列的方式解题 @@ -401,7 +401,8 @@ func maxSlidingWindow(nums []int, k int) []int { } ``` -Javascript: +### Javascript: + ```javascript /** * @param {number[]} nums @@ -449,7 +450,7 @@ var maxSlidingWindow = function (nums, k) { }; ``` -TypeScript: +### TypeScript: ```typescript function maxSlidingWindow(nums: number[], k: number): number[] { @@ -497,7 +498,9 @@ function maxSlidingWindow(nums: number[], k: number): number[] { }; ``` -Swift: +### Swift: + +解法一: ```Swift /// 双向链表 @@ -638,7 +641,8 @@ func maxSlidingWindow(_ nums: [Int], _ k: Int) -> [Int] { return result } ``` -Scala: +### Scala: + ```scala import scala.collection.mutable.ArrayBuffer object Solution { @@ -686,8 +690,8 @@ class MyQueue { } ``` +### PHP: -PHP: ```php class Solution { /** @@ -764,7 +768,8 @@ class MyQueue{ } ``` -C#: +### C#: + ```csharp class myDequeue{ private LinkedList linkedList = new LinkedList(); @@ -805,7 +810,7 @@ class myDequeue{ } ``` -rust: +### Rust: ```rust impl Solution { From 0e4f91d81d68b53269f33aa994ecab626202243b Mon Sep 17 00:00:00 2001 From: jinbudaily <18336218010@163.com> Date: Thu, 20 Jul 2023 15:13:29 +0800 Subject: [PATCH 069/122] =?UTF-8?q?=E6=9B=B4=E6=96=B0=200347.=E5=89=8Dk?= =?UTF-8?q?=E4=B8=AA=E9=AB=98=E9=A2=91=E5=85=83=E7=B4=A0=20=E6=8E=92?= =?UTF-8?q?=E7=89=88=E6=A0=BC=E5=BC=8F=E4=BF=AE=E5=A4=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- problems/0347.前K个高频元素.md | 33 +++++++++++++++++++-------------- 1 file changed, 19 insertions(+), 14 deletions(-) diff --git a/problems/0347.前K个高频元素.md b/problems/0347.前K个高频元素.md index 6c8b51b1..b3063111 100644 --- a/problems/0347.前K个高频元素.md +++ b/problems/0347.前K个高频元素.md @@ -5,8 +5,6 @@

参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!

- - > 前K个大数问题,老生常谈,不得不谈 # 347.前 K 个高频元素 @@ -29,9 +27,11 @@ * 题目数据保证答案唯一,换句话说,数组中前 k 个高频元素的集合是唯一的。 * 你可以按任意顺序返回答案。 -# 思路 +## 算法公开课 -《代码随想录》算法视频公开课:[优先级队列正式登场!大顶堆、小顶堆该怎么用?| LeetCode:347.前 K 个高频元素](https://www.bilibili.com/video/BV1Xg41167Lz),相信结合视频在看本篇题解,更有助于大家对本题的理解。 +**[《代码随想录》算法视频公开课](https://programmercarl.com/other/gongkaike.html):[优先级队列正式登场!大顶堆、小顶堆该怎么用?| LeetCode:347.前 K 个高频元素](https://www.bilibili.com/video/BV1Xg41167Lz),相信结合视频再看本篇题解,更有助于大家对本题的理解**。 + +## 思路 这道题目主要涉及到如下三块内容: 1. 要统计元素出现频率 @@ -122,7 +122,7 @@ public: * 时间复杂度: O(nlogk) * 空间复杂度: O(n) -# 拓展 +## 拓展 大家对这个比较运算在建堆时是如何应用的,为什么左大于右就会建立小顶堆,反而建立大顶堆比较困惑。 确实 例如我们在写快排的cmp函数的时候,`return left>right` 就是从大到小,`return left + From f7b87e625a9fab65b30d19b5252aef26c869fbdb Mon Sep 17 00:00:00 2001 From: jinbudaily <18336218010@163.com> Date: Thu, 20 Jul 2023 15:15:50 +0800 Subject: [PATCH 070/122] =?UTF-8?q?=E6=9B=B4=E6=96=B0=20=E6=A0=88=E4=B8=8E?= =?UTF-8?q?=E9=98=9F=E5=88=97=E6=80=BB=E7=BB=93=20=E6=8E=92=E7=89=88?= =?UTF-8?q?=E6=A0=BC=E5=BC=8F=E4=BF=AE=E5=A4=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- problems/栈与队列总结.md | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/problems/栈与队列总结.md b/problems/栈与队列总结.md index c3132201..31ce9554 100644 --- a/problems/栈与队列总结.md +++ b/problems/栈与队列总结.md @@ -3,9 +3,9 @@

参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!

+# 栈与队列总结篇 - -# 栈与队列的理论基础 +## 栈与队列的理论基础 首先我们在[栈与队列:来看看栈和队列不为人知的一面](https://programmercarl.com/栈与队列理论基础.html)中讲解了栈和队列的理论基础。 @@ -37,9 +37,9 @@ **一个队列在模拟栈弹出元素的时候只要将队列头部的元素(除了最后一个元素外) 重新添加到队列尾部,此时在去弹出元素就是栈的顺序了。** -# 栈经典题目 +## 栈经典题目 -## 栈在系统中的应用 +### 栈在系统中的应用 如果还记得编译原理的话,编译器在 词法分析的过程中处理括号、花括号等这个符号的逻辑,就是使用了栈这种数据结构。 @@ -59,7 +59,7 @@ cd a/b/c/../../ **所以数据结构与算法的应用往往隐藏在我们看不到的地方!** -## 括号匹配问题 +### 括号匹配问题 在[栈与队列:系统中处处都是栈的应用](https://programmercarl.com/0020.有效的括号.html)中我们讲解了括号匹配问题。 @@ -75,23 +75,23 @@ cd a/b/c/../../ 这里还有一些技巧,在匹配左括号的时候,右括号先入栈,就只需要比较当前元素和栈顶相不相等就可以了,比左括号先入栈代码实现要简单的多了! -## 字符串去重问题 +### 字符串去重问题 在[栈与队列:匹配问题都是栈的强项](https://programmercarl.com/1047.删除字符串中的所有相邻重复项.html)中讲解了字符串去重问题。 1047. 删除字符串中的所有相邻重复项 思路就是可以把字符串顺序放到一个栈中,然后如果相同的话 栈就弹出,这样最后栈里剩下的元素都是相邻不相同的元素了。 -## 逆波兰表达式问题 +### 逆波兰表达式问题 在[栈与队列:有没有想过计算机是如何处理表达式的?](https://programmercarl.com/0150.逆波兰表达式求值.html)中讲解了求逆波兰表达式。 本题中每一个子表达式要得出一个结果,然后拿这个结果再进行运算,那么**这岂不就是一个相邻字符串消除的过程,和[栈与队列:匹配问题都是栈的强项](https://programmercarl.com/1047.删除字符串中的所有相邻重复项.html)中的对对碰游戏是不是就非常像了。** -# 队列的经典题目 +## 队列的经典题目 -## 滑动窗口最大值问题 +### 滑动窗口最大值问题 在[栈与队列:滑动窗口里求最大值引出一个重要数据结构](https://programmercarl.com/0239.滑动窗口最大值.html)中讲解了一种数据结构:单调队列。 @@ -119,7 +119,7 @@ cd a/b/c/../../ 我们用deque作为单调队列的底层数据结构,C++中deque是stack和queue默认的底层实现容器(这个我们之前已经讲过),deque是可以两边扩展的,而且deque里元素并不是严格的连续分布的。 -## 求前 K 个高频元素 +### 求前 K 个高频元素 在[栈与队列:求前 K 个高频元素和队列有啥关系?](https://programmercarl.com/0347.前K个高频元素.html)中讲解了求前 K 个高频元素。 @@ -143,7 +143,7 @@ cd a/b/c/../../ 所以排序的过程的时间复杂度是$O(\log k)$,整个算法的时间复杂度是$O(n\log k)$。 -# 总结 +## 总结 在栈与队列系列中,我们强调栈与队列的基础,也是很多同学容易忽视的点。 @@ -162,3 +162,4 @@ cd a/b/c/../../ + From c6bcd423d6bdab6375e3af8bc7c3c01bfc0518a1 Mon Sep 17 00:00:00 2001 From: jinbudaily <18336218010@163.com> Date: Thu, 20 Jul 2023 15:48:05 +0800 Subject: [PATCH 071/122] =?UTF-8?q?=E6=9B=B4=E6=96=B0=20=E4=BA=8C=E5=8F=89?= =?UTF-8?q?=E6=A0=91=E7=90=86=E8=AE=BA=E5=9F=BA=E7=A1=80=20=E6=8E=92?= =?UTF-8?q?=E7=89=88=E6=A0=BC=E5=BC=8F=E4=BF=AE=E5=A4=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- problems/二叉树理论基础.md | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/problems/二叉树理论基础.md b/problems/二叉树理论基础.md index 4098cf1f..184dba60 100644 --- a/problems/二叉树理论基础.md +++ b/problems/二叉树理论基础.md @@ -8,8 +8,11 @@ # 二叉树理论基础篇 +## 算法公开课 -《代码随想录》算法视频公开课:[关于二叉树,你该了解这些!](https://www.bilibili.com/video/BV1Hy4y1t7ij),相信结合视频在看本篇题解,更有助于大家对本题的理解。 +**[《代码随想录》算法视频公开课](https://programmercarl.com/other/gongkaike.html):[关于二叉树,你该了解这些!](https://www.bilibili.com/video/BV1Hy4y1t7ij),相信结合视频再看本篇题解,更有助于大家对本题的理解**。 + +## 题目分类 题目分类大纲如下: @@ -189,8 +192,7 @@ struct TreeNode { ## 其他语言版本 - -Java: +### Java: ```java public class TreeNode { @@ -208,8 +210,7 @@ public class TreeNode { } ``` - -Python: +### Python: ```python class TreeNode: @@ -219,7 +220,7 @@ class TreeNode: self.right = right ``` -Go: +### Go: ```go type TreeNode struct { @@ -229,7 +230,7 @@ type TreeNode struct { } ``` -JavaScript: +### JavaScript: ```javascript function TreeNode(val, left, right) { @@ -239,7 +240,7 @@ function TreeNode(val, left, right) { } ``` -TypeScript: +### TypeScript: ```typescript class TreeNode { @@ -254,7 +255,7 @@ class TreeNode { } ``` -Swift: +### Swift: ```Swift class TreeNode { @@ -271,7 +272,7 @@ class TreeNode { } ``` -Scala: +### Scala: ```scala class TreeNode(_value: Int = 0, _left: TreeNode = null, _right: TreeNode = null) { @@ -281,7 +282,7 @@ class TreeNode(_value: Int = 0, _left: TreeNode = null, _right: TreeNode = null) } ``` -rust: +### Rust: ```rust #[derive(Debug, PartialEq, Eq)] From 7807b5e7989751cd9e5d2df8da6821438e01c378 Mon Sep 17 00:00:00 2001 From: jinbudaily <18336218010@163.com> Date: Thu, 20 Jul 2023 15:53:16 +0800 Subject: [PATCH 072/122] =?UTF-8?q?=E6=9B=B4=E6=96=B0=20=E4=BA=8C=E5=8F=89?= =?UTF-8?q?=E6=A0=91=E7=9A=84=E9=80=92=E5=BD=92=E9=81=8D=E5=8E=86=20?= =?UTF-8?q?=E6=8E=92=E7=89=88=E6=A0=BC=E5=BC=8F=E4=BF=AE=E5=A4=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- problems/二叉树的递归遍历.md | 37 ++++++++++++++++++------------------ 1 file changed, 19 insertions(+), 18 deletions(-) diff --git a/problems/二叉树的递归遍历.md b/problems/二叉树的递归遍历.md index 92f342f0..730b18ac 100644 --- a/problems/二叉树的递归遍历.md +++ b/problems/二叉树的递归遍历.md @@ -4,15 +4,15 @@

参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!

- +> 一看就会,一写就废! # 二叉树的递归遍历 +## 算法公开课 -《代码随想录》算法视频公开课:[每次写递归都要靠直觉? 这次带你学透二叉树的递归遍历!](https://www.bilibili.com/video/BV1Wh411S7xt),相信结合视频在看本篇题解,更有助于大家对本题的理解。 +**[《代码随想录》算法视频公开课](https://programmercarl.com/other/gongkaike.html):[每次写递归都要靠直觉? 这次带你学透二叉树的递归遍历!](https://www.bilibili.com/video/BV1Wh411S7xt),相信结合视频再看本篇题解,更有助于大家对本题的理解**。 - -> 一看就会,一写就废! +## 思路 这次我们要好好谈一谈递归,为什么很多同学看递归算法都是“一看就会,一写就废”。 @@ -109,14 +109,10 @@ void traversal(TreeNode* cur, vector& vec) { 可能有同学感觉前后中序遍历的递归太简单了,要打迭代法(非递归),别急,我们明天打迭代法,打个通透! +## 其他语言版本 +### Java: - - -# 其他语言版本 - - -Java: ```Java // 前序遍历·递归·LC144_二叉树的前序遍历 class Solution { @@ -171,7 +167,8 @@ class Solution { } ``` -Python: +### Python: + ```python # 前序遍历-递归-LC144_二叉树的前序遍历 # Definition for a binary tree node. @@ -219,7 +216,7 @@ class Solution: return left + right + [root.val] ``` -Go: +### Go: 前序遍历: ```go @@ -273,7 +270,7 @@ func postorderTraversal(root *TreeNode) (res []int) { } ``` -Javascript版本: +### Javascript: 前序遍历: ```Javascript @@ -327,7 +324,7 @@ var postorderTraversal = function(root) { }; ``` -TypeScript: +### TypeScript: ```typescript // 前序遍历 @@ -370,7 +367,7 @@ function postorderTraversal(node: TreeNode | null): number[] { } ``` -C: +### C: ```c //前序遍历: @@ -422,8 +419,9 @@ int* postorderTraversal(struct TreeNode* root, int* returnSize){ } ``` -Swift: +### Swift: 前序遍历:(144.二叉树的前序遍历) + ```Swift func preorderTraversal(_ root: TreeNode?) -> [Int] { var res = [Int]() @@ -473,7 +471,10 @@ func postorder(_ root: TreeNode?, res: inout [Int]) { res.append(root!.val) } ``` -Scala: 前序遍历:(144.二叉树的前序遍历) +### Scala: + + 前序遍历:(144.二叉树的前序遍历) + ```scala object Solution { import scala.collection.mutable.ListBuffer @@ -525,7 +526,7 @@ object Solution { } ``` -rust: +### Rust: ```rust use std::cell::RefCell; From a13bb8292123ceded30c12bf7e713468fc29e50f Mon Sep 17 00:00:00 2001 From: jinbudaily <18336218010@163.com> Date: Thu, 20 Jul 2023 16:07:52 +0800 Subject: [PATCH 073/122] =?UTF-8?q?=E6=9B=B4=E6=96=B0=20=E4=BA=8C=E5=8F=89?= =?UTF-8?q?=E6=A0=91=E7=9A=84=E8=BF=AD=E4=BB=A3=E9=81=8D=E5=8E=86=20?= =?UTF-8?q?=E6=8E=92=E7=89=88=E6=A0=BC=E5=BC=8F=E4=BF=AE=E5=A4=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- problems/二叉树的迭代遍历.md | 50 +++++++++++++++++------------------- 1 file changed, 24 insertions(+), 26 deletions(-) diff --git a/problems/二叉树的迭代遍历.md b/problems/二叉树的迭代遍历.md index 8b241465..69007995 100644 --- a/problems/二叉树的迭代遍历.md +++ b/problems/二叉树的迭代遍历.md @@ -4,16 +4,17 @@

参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!

+> 听说还可以用非递归的方式 # 二叉树的迭代遍历 -《代码随想录》算法视频公开课: -* [写出二叉树的非递归遍历很难么?(前序和后序)](https://www.bilibili.com/video/BV15f4y1W7i2) -* [写出二叉树的非递归遍历很难么?(中序))](https://www.bilibili.com/video/BV1Zf4y1a77g) -相信结合视频在看本篇题解,更有助于大家对本题的理解。 +## 算法公开课 +[《代码随想录》算法视频公开课](https://programmercarl.com/other/gongkaike.html): -> 听说还可以用非递归的方式 +* **[写出二叉树的非递归遍历很难么?(前序和后序)](https://www.bilibili.com/video/BV15f4y1W7i2)** +* **[写出二叉树的非递归遍历很难么?(中序))](https://www.bilibili.com/video/BV1Zf4y1a77g)** +**相信结合视频在看本篇题解,更有助于大家对本题的理解。** 看完本篇大家可以使用迭代法,再重新解决如下三道leetcode上的题目: @@ -21,13 +22,15 @@ * [94.二叉树的中序遍历](https://leetcode.cn/problems/binary-tree-inorder-traversal/) * [145.二叉树的后序遍历](https://leetcode.cn/problems/binary-tree-postorder-traversal/) +## 思路 + 为什么可以用迭代法(非递归的方式)来实现二叉树的前后中序遍历呢? 我们在[栈与队列:匹配问题都是栈的强项](https://programmercarl.com/1047.删除字符串中的所有相邻重复项.html)中提到了,**递归的实现就是:每一次递归调用都会把函数的局部变量、参数值和返回地址等压入调用栈中**,然后递归返回的时候,从栈顶弹出上一次递归的各项参数,所以这就是递归为什么可以返回上一层位置的原因。 此时大家应该知道我们用栈也可以是实现二叉树的前后中序遍历了。 -## 前序遍历(迭代法) +### 前序遍历(迭代法) 我们先看一下前序遍历。 @@ -69,7 +72,7 @@ public: 但接下来,**再用迭代法写中序遍历的时候,会发现套路又不一样了,目前的前序遍历的逻辑无法直接应用到中序遍历上。** -## 中序遍历(迭代法) +### 中序遍历(迭代法) 为了解释清楚,我说明一下 刚刚在迭代的过程中,其实我们有两个操作: @@ -112,7 +115,7 @@ public: ``` -## 后序遍历(迭代法) +### 后序遍历(迭代法) 再来看后序遍历,先序遍历是中左右,后续遍历是左右中,那么我们只需要调整一下先序遍历的代码顺序,就变成中右左的遍历顺序,然后在反转result数组,输出的结果顺序就是左右中了,如下图: @@ -142,7 +145,7 @@ public: ``` -# 总结 +## 总结 此时我们用迭代法写出了二叉树的前后中序遍历,大家可以看出前序和中序是完全两种代码风格,并不像递归写法那样代码稍做调整,就可以实现前后中序。 @@ -155,11 +158,9 @@ public: 当然可以,这种写法,还不是很好理解,我们将在下一篇文章里重点讲解,敬请期待! +## 其他语言版本 - -# 其他语言版本 - -Java: +### Java: ```java // 前序遍历顺序:中-左-右,入栈顺序:中-右-左 @@ -233,10 +234,7 @@ class Solution { } ``` - - - -Python: +### Python: ```python # 前序遍历-迭代-LC144_二叉树的前序遍历 @@ -281,7 +279,7 @@ class Solution: # 取栈顶元素右结点 cur = cur.right return result - ``` +``` ```python # 后序遍历-迭代-LC145_二叉树的后序遍历 @@ -303,10 +301,9 @@ class Solution: stack.append(node.right) # 将最终的数组翻转 return result[::-1] -``` + ``` - -Go: +### Go: > 迭代法前序遍历 @@ -400,7 +397,7 @@ func inorderTraversal(root *TreeNode) []int { } ``` -javaScript: +### JavaScript: ```js @@ -464,7 +461,7 @@ var postorderTraversal = function(root, res = []) { }; ``` -TypeScript: +### TypeScript: ```typescript // 前序遍历(迭代法) @@ -519,7 +516,7 @@ function postorderTraversal(root: TreeNode | null): number[] { }; ``` -Swift: +### Swift: ```swift // 前序遍历迭代法 @@ -578,7 +575,8 @@ func inorderTraversal(_ root: TreeNode?) -> [Int] { return result } ``` -Scala: +### Scala: + ```scala // 前序遍历(迭代法) object Solution { @@ -645,7 +643,7 @@ object Solution { } ``` -rust: +### Rust: ```rust use std::cell::RefCell; From cc510357c1fe6f0cf25fd4e800c2a89b03b4659f Mon Sep 17 00:00:00 2001 From: jinbudaily <18336218010@163.com> Date: Thu, 20 Jul 2023 16:22:00 +0800 Subject: [PATCH 074/122] =?UTF-8?q?=E6=9B=B4=E6=96=B0=20=E4=BA=8C=E5=8F=89?= =?UTF-8?q?=E6=A0=91=E7=9A=84=E7=BB=9F=E4=B8=80=E8=BF=AD=E4=BB=A3=E6=B3=95?= =?UTF-8?q?=20=E6=8E=92=E7=89=88=E6=A0=BC=E5=BC=8F=E4=BF=AE=E5=A4=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- problems/二叉树的统一迭代法.md | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/problems/二叉树的统一迭代法.md b/problems/二叉树的统一迭代法.md index 27464269..8089af64 100644 --- a/problems/二叉树的统一迭代法.md +++ b/problems/二叉树的统一迭代法.md @@ -5,10 +5,11 @@

参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!

+> 统一写法是一种什么感觉 # 二叉树的统一迭代法 -> 统一写法是一种什么感觉 +## 思路 此时我们在[二叉树:一入递归深似海,从此offer是路人](https://programmercarl.com/二叉树的递归遍历.html)中用递归的方式,实现了二叉树前中后序的遍历。 @@ -28,7 +29,7 @@ 如何标记呢,**就是要处理的节点放入栈之后,紧接着放入一个空指针作为标记。** 这种方法也可以叫做标记法。 -## 迭代法中序遍历 +### 迭代法中序遍历 中序遍历代码如下:(详细注释) @@ -71,7 +72,7 @@ public: 此时我们再来看前序遍历代码。 -## 迭代法前序遍历 +### 迭代法前序遍历 迭代法前序遍历代码如下: (**注意此时我们和中序遍历相比仅仅改变了两行代码的顺序**) @@ -102,7 +103,7 @@ public: }; ``` -## 迭代法后序遍历 +### 迭代法后序遍历 后续遍历代码如下: (**注意此时我们和中序遍历相比仅仅改变了两行代码的顺序**) @@ -143,15 +144,11 @@ public: 所以大家根据自己的个人喜好,对于二叉树的前中后序遍历,选择一种自己容易理解的递归和迭代法。 +## 其他语言版本 - - - -# 其他语言版本 - - -Java: +### Java: 迭代法前序遍历代码如下: + ```java class Solution { public List preorderTraversal(TreeNode root) { @@ -235,7 +232,7 @@ class Solution { } ``` -Python: +### Python: 迭代法前序遍历: ```python @@ -309,7 +306,8 @@ class Solution: return result ``` -Go: +### Go: + > 前序遍历统一迭代法 ```GO @@ -442,7 +440,7 @@ func postorderTraversal(root *TreeNode) []int { } ``` -javaScript: +### JavaScript: > 前序遍历统一迭代法 @@ -522,7 +520,7 @@ var postorderTraversal = function(root, res = []) { ``` -TypeScript: +### TypeScript: ```typescript // 前序遍历(迭代法) @@ -591,7 +589,8 @@ function postorderTraversal(root: TreeNode | null): number[] { return res; }; ``` -Scala: +### Scala: + ```scala // 前序遍历 object Solution { @@ -667,7 +666,7 @@ object Solution { } ``` -rust: +### Rust: ```rust impl Solution{ @@ -747,3 +746,4 @@ impl Solution{ + From 8e34d5ff5749229eeaa7dce33e1ed74c0dd992a2 Mon Sep 17 00:00:00 2001 From: jinbudaily <18336218010@163.com> Date: Thu, 20 Jul 2023 19:17:38 +0800 Subject: [PATCH 075/122] =?UTF-8?q?=E6=9B=B4=E6=96=B0=200102.=E4=BA=8C?= =?UTF-8?q?=E5=8F=89=E6=A0=91=E7=9A=84=E5=B1=82=E5=BA=8F=E9=81=8D=E5=8E=86?= =?UTF-8?q?=20=E6=8E=92=E7=89=88=E6=A0=BC=E5=BC=8F=E4=BF=AE=E5=A4=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- problems/0102.二叉树的层序遍历.md | 284 ++++++++++++++++-------------- 1 file changed, 149 insertions(+), 135 deletions(-) diff --git a/problems/0102.二叉树的层序遍历.md b/problems/0102.二叉树的层序遍历.md index c2ad9508..ce9a247c 100644 --- a/problems/0102.二叉树的层序遍历.md +++ b/problems/0102.二叉树的层序遍历.md @@ -8,21 +8,23 @@ # 二叉树层序遍历登场! -《代码随想录》算法视频公开课:[讲透二叉树的层序遍历 | 广度优先搜索 | LeetCode:102.二叉树的层序遍历](https://www.bilibili.com/video/BV1GY4y1u7b2),相信结合视频在看本篇题解,更有助于大家对本题的理解。 +## 算法公开课 + +**[《代码随想录》算法视频公开课](https://programmercarl.com/other/gongkaike.html):[讲透二叉树的层序遍历 | 广度优先搜索 | LeetCode:102.二叉树的层序遍历](https://www.bilibili.com/video/BV1GY4y1u7b2),相信结合视频再看本篇题解,更有助于大家对本题的理解**。 学会二叉树的层序遍历,可以一口气打完以下十题: -* 102.二叉树的层序遍历 -* 107.二叉树的层次遍历II -* 199.二叉树的右视图 -* 637.二叉树的层平均值 -* 429.N叉树的层序遍历 -* 515.在每个树行中找最大值 -* 116.填充每个节点的下一个右侧节点指针 -* 117.填充每个节点的下一个右侧节点指针II -* 104.二叉树的最大深度 -* 111.二叉树的最小深度 +* [102.二叉树的层序遍历](https://leetcode.cn/problems/binary-tree-level-order-traversal/) +* [107.二叉树的层次遍历II](https://leetcode.cn/problems/binary-tree-level-order-traversal-ii/) +* [199.二叉树的右视图](https://leetcode.cn/problems/binary-tree-right-side-view/) +* [637.二叉树的层平均值](https://leetcode.cn/problems/binary-tree-right-side-view/) +* [429.N叉树的层序遍历](https://leetcode.cn/problems/n-ary-tree-level-order-traversal/) +* [515.在每个树行中找最大值](https://leetcode.cn/problems/find-largest-value-in-each-tree-row/) +* [116.填充每个节点的下一个右侧节点指针](https://leetcode.cn/problems/populating-next-right-pointers-in-each-node/) +* [117.填充每个节点的下一个右侧节点指针II](https://leetcode.cn/problems/populating-next-right-pointers-in-each-node-ii/) +* [104.二叉树的最大深度](https://leetcode.cn/problems/maximum-depth-of-binary-tree/) +* [111.二叉树的最小深度](https://leetcode.cn/problems/minimum-depth-of-binary-tree/) @@ -31,7 +33,7 @@ -# 102.二叉树的层序遍历 +## 102.二叉树的层序遍历 [力扣题目链接](https://leetcode.cn/problems/binary-tree-level-order-traversal/) @@ -39,7 +41,7 @@ ![102.二叉树的层序遍历](https://code-thinking-1253855093.file.myqcloud.com/pics/20210203144842988.png) -思路: +### 思路 我们之前讲过了三篇关于二叉树的深度优先遍历的文章: @@ -63,7 +65,7 @@ 代码如下:**这份代码也可以作为二叉树层序遍历的模板,打十个就靠它了**。 -C++代码: +c++代码如下: ```CPP class Solution { @@ -111,7 +113,9 @@ public: }; ``` -java: +### 其他语言版本 + +#### Java: ```Java // 102.二叉树的层序遍历 @@ -167,7 +171,7 @@ class Solution { } ``` -python3代码: +#### Python: ```python @@ -219,12 +223,9 @@ class Solution: self.helper(node.left, level + 1, levels) self.helper(node.right, level + 1, levels) - ``` - - -go: +#### Go: ```go /** @@ -320,7 +321,7 @@ func levelOrder(root *TreeNode) (res [][]int) { } ``` -javascript代码: +#### Javascript: ```javascript var levelOrder = function(root) { @@ -350,7 +351,7 @@ var levelOrder = function(root) { ``` -TypeScript: +#### TypeScript: ```typescript function levelOrder(root: TreeNode | null): number[][] { @@ -377,7 +378,7 @@ function levelOrder(root: TreeNode | null): number[][] { }; ``` -Swift: +#### Swift: ```swift func levelOrder(_ root: TreeNode?) -> [[Int]] { @@ -403,7 +404,7 @@ func levelOrder(_ root: TreeNode?) -> [[Int]] { } ``` -Scala: +#### Scala: ```scala // 102.二叉树的层序遍历 @@ -430,7 +431,7 @@ object Solution { } ``` -Rust: +#### Rust: ```rust use std::cell::RefCell; @@ -466,7 +467,7 @@ impl Solution { **此时我们就掌握了二叉树的层序遍历了,那么如下九道力扣上的题目,只需要修改模板的两三行代码(不能再多了),便可打倒!** -# 107.二叉树的层次遍历 II +## 107.二叉树的层次遍历 II [力扣题目链接](https://leetcode.cn/problems/binary-tree-level-order-traversal-ii/) @@ -474,7 +475,7 @@ impl Solution { ![107.二叉树的层次遍历II](https://code-thinking-1253855093.file.myqcloud.com/pics/20210203151058308.png) -思路: +### 思路 相对于102.二叉树的层序遍历,就是最后把result数组反转一下就可以了。 @@ -506,7 +507,9 @@ public: }; ``` -python代码: +### 其他语言版本 + +#### Python: ```python class Solution: @@ -537,7 +540,7 @@ class Solution: return result[::-1] ``` -Java: +#### Java: ```java // 107. 二叉树的层序遍历 II @@ -618,12 +621,10 @@ class Solution { return ans; } -} + ``` - - -go: +#### Go: ```GO /** @@ -662,7 +663,7 @@ func levelOrderBottom(root *TreeNode) [][]int { } ``` -javascript代码 +#### Javascript: ```javascript var levelOrderBottom = function(root) { @@ -688,7 +689,7 @@ var levelOrderBottom = function(root) { }; ``` -TypeScript: +#### TypeScript: ```typescript function levelOrderBottom(root: TreeNode | null): number[][] { @@ -711,7 +712,7 @@ function levelOrderBottom(root: TreeNode | null): number[][] { }; ``` -Swift: +#### Swift: ```swift func levelOrderBottom(_ root: TreeNode?) -> [[Int]] { @@ -737,8 +738,7 @@ func levelOrderBottom(_ root: TreeNode?) -> [[Int]] { } ``` - -Scala: +#### Scala: ```scala // 107.二叉树的层次遍历II @@ -764,7 +764,10 @@ object Solution { res.reverse.toList } -Rust: + +``` + +#### Rust: ```rust use std::cell::RefCell; @@ -796,7 +799,7 @@ impl Solution { } ``` -# 199.二叉树的右视图 +## 199.二叉树的右视图 [力扣题目链接](https://leetcode.cn/problems/binary-tree-right-side-view/) @@ -804,7 +807,7 @@ impl Solution { ![199.二叉树的右视图](https://code-thinking-1253855093.file.myqcloud.com/pics/20210203151307377.png) -思路: +### 思路 层序遍历的时候,判断是否遍历到单层的最后面的元素,如果是,就放进result数组中,随后返回result就可以了。 @@ -832,7 +835,9 @@ public: }; ``` -python代码: +### 其他语言版本 + +#### Python: ```python # Definition for a binary tree node. @@ -866,8 +871,7 @@ class Solution: return right_view ``` - -Java: +#### Java: ```java // 199.二叉树的右视图 @@ -911,7 +915,7 @@ public class N0199 { } ``` -go: +#### Go: ```GO /** @@ -945,8 +949,7 @@ func rightSideView(root *TreeNode) []int { } ``` - -javascript代码: +#### Javascript: ```javascript var rightSideView = function(root) { @@ -972,7 +975,7 @@ var rightSideView = function(root) { }; ``` -TypeScript: +#### TypeScript: ```typescript function rightSideView(root: TreeNode | null): number[] { @@ -992,7 +995,7 @@ function rightSideView(root: TreeNode | null): number[] { }; ``` -Swift: +#### Swift: ```swift func rightSideView(_ root: TreeNode?) -> [Int] { @@ -1017,7 +1020,7 @@ func rightSideView(_ root: TreeNode?) -> [Int] { } ``` -Scala: +#### Scala: ```scala // 199.二叉树的右视图 @@ -1043,7 +1046,7 @@ object Solution { } ``` -rust: +#### Rust: ```rust use std::cell::RefCell; @@ -1076,7 +1079,7 @@ impl Solution { } ``` -# 637.二叉树的层平均值 +## 637.二叉树的层平均值 [力扣题目链接](https://leetcode.cn/problems/average-of-levels-in-binary-tree/) @@ -1084,7 +1087,7 @@ impl Solution { ![637.二叉树的层平均值](https://code-thinking-1253855093.file.myqcloud.com/pics/20210203151350500.png) -思路: +### 思路 本题就是层序遍历的时候把一层求个总和在取一个均值。 @@ -1115,7 +1118,9 @@ public: ``` -python代码: +### 其他语言版本 + +#### Python: ```python class Solution: @@ -1155,7 +1160,7 @@ class Solution: return averages ``` -java: +#### Java: ```java // 637. 二叉树的层平均值 @@ -1197,7 +1202,7 @@ public class N0637 { } ``` -go: +#### Go: ```GO /** @@ -1235,7 +1240,7 @@ func averageOfLevels(root *TreeNode) []float64 { } ``` -javascript代码: +#### Javascript: ```javascript var averageOfLevels = function(root) { @@ -1262,7 +1267,7 @@ var averageOfLevels = function(root) { }; ``` -TypeScript: +#### TypeScript: ```typescript function averageOfLevels(root: TreeNode | null): number[] { @@ -1286,7 +1291,7 @@ function averageOfLevels(root: TreeNode | null): number[] { }; ``` -Swift: +#### Swift: ```swift func averageOfLevels(_ root: TreeNode?) -> [Double] { @@ -1313,7 +1318,7 @@ func averageOfLevels(_ root: TreeNode?) -> [Double] { } ``` -Scala: +#### Scala: ```scala // 637.二叉树的层平均值 @@ -1339,7 +1344,7 @@ object Solution { } ``` -rust: +#### Rust: ```rust use std::cell::RefCell; @@ -1372,7 +1377,7 @@ impl Solution { } ``` -# 429.N叉树的层序遍历 +## 429.N叉树的层序遍历 [力扣题目链接](https://leetcode.cn/problems/n-ary-tree-level-order-traversal/) @@ -1390,8 +1395,7 @@ impl Solution { [5,6] ] - -思路: +### 思路 这道题依旧是模板题,只不过一个节点有多个孩子了 @@ -1423,7 +1427,9 @@ public: }; ``` -python代码: +### 其他语言版本 + +#### Python: ```python """ @@ -1475,7 +1481,7 @@ class Solution: return result ``` -java: +#### Java: ```java // 429. N 叉树的层序遍历 @@ -1535,8 +1541,7 @@ public class N0429 { } ``` - -go: +#### Go: ```GO /** @@ -1567,7 +1572,7 @@ func levelOrder(root *Node) [][]int { } ``` -JavaScript代码: +#### JavaScript: ```JavaScript var levelOrder = function(root) { @@ -1596,7 +1601,7 @@ var levelOrder = function(root) { }; ``` -TypeScript: +#### TypeScript: ```typescript function levelOrder(root: Node | null): number[][] { @@ -1618,7 +1623,7 @@ function levelOrder(root: Node | null): number[][] { }; ``` -Swift: +#### Swift: ```swift func levelOrder(_ root: Node?) -> [[Int]] { @@ -1643,7 +1648,7 @@ func levelOrder(_ root: Node?) -> [[Int]] { } ``` -Scala: +#### Scala: ```scala // 429.N叉树的层序遍历 @@ -1672,7 +1677,7 @@ object Solution { } ``` -rust: +#### Rust: ```rust pub struct Solution; @@ -1720,7 +1725,7 @@ impl Solution { } ``` -# 515.在每个树行中找最大值 +## 515.在每个树行中找最大值 [力扣题目链接](https://leetcode.cn/problems/find-largest-value-in-each-tree-row/) @@ -1728,7 +1733,7 @@ impl Solution { ![515.在每个树行中找最大值](https://code-thinking-1253855093.file.myqcloud.com/pics/20210203151532153.png) -思路: +### 思路 层序遍历,取每一层的最大值 @@ -1758,7 +1763,9 @@ public: }; ``` -python代码: +### 其他语言版本 + +#### Python: ```python # Definition for a binary tree node. @@ -1794,7 +1801,7 @@ class Solution: return result ``` -java代码: +#### Java: ```java class Solution { @@ -1820,7 +1827,7 @@ class Solution { } ``` -go: +#### Go: ```GO /** @@ -1864,7 +1871,7 @@ func max(x, y int) int { } ``` -javascript代码: +#### Javascript: ```javascript var largestValues = function(root) { @@ -1890,7 +1897,7 @@ var largestValues = function(root) { }; ``` -TypeScript: +#### TypeScript: ```typescript function largestValues(root: TreeNode | null): number[] { @@ -1916,7 +1923,7 @@ function largestValues(root: TreeNode | null): number[] { }; ``` -Swift: +#### Swift: ```swift func largestValues(_ root: TreeNode?) -> [Int] { @@ -1943,7 +1950,7 @@ func largestValues(_ root: TreeNode?) -> [Int] { } ``` -Scala: +#### Scala: ```scala // 515.在每个树行中找最大值 @@ -1970,7 +1977,7 @@ object Solution { } ``` -rust: +#### Rust: ```rust use std::cell::RefCell; @@ -2002,7 +2009,7 @@ impl Solution { } ``` -# 116.填充每个节点的下一个右侧节点指针 +## 116.填充每个节点的下一个右侧节点指针 [力扣题目链接](https://leetcode.cn/problems/populating-next-right-pointers-in-each-node/) @@ -2024,7 +2031,7 @@ struct Node { ![116.填充每个节点的下一个右侧节点指针](https://code-thinking-1253855093.file.myqcloud.com/pics/20210203152044855.jpg) -思路: +### 思路 本题依然是层序遍历,只不过在单层遍历的时候记录一下本层的头部节点,然后在遍历的时候让前一个节点指向本节点就可以了 @@ -2063,7 +2070,9 @@ public: }; ``` -java代码: +### 其他语言版本 + +#### Java: ```java class Solution { @@ -2093,7 +2102,7 @@ class Solution { } ``` -python代码: +#### Python: ```python """ @@ -2133,7 +2142,7 @@ class Solution: return root ``` -go: +#### Go: ```GO /** @@ -2173,7 +2182,7 @@ func connect(root *Node) *Node { ``` -JavaScript: +#### JavaScript: ```javascript /** @@ -2209,7 +2218,7 @@ var connect = function(root) { ``` -TypeScript: +#### TypeScript: ```typescript function connect(root: Node | null): Node | null { @@ -2234,7 +2243,7 @@ function connect(root: Node | null): Node | null { }; ``` -Swift: +#### Swift: ```swift func connect(_ root: Node?) -> Node? { @@ -2266,7 +2275,7 @@ func connect(_ root: Node?) -> Node? { } ``` -Scala: +#### Scala: ```scala // 116.填充每个节点的下一个右侧节点指针 @@ -2297,11 +2306,11 @@ object Solution { } ``` -# 117.填充每个节点的下一个右侧节点指针II +## 117.填充每个节点的下一个右侧节点指针II [力扣题目链接](https://leetcode.cn/problems/populating-next-right-pointers-in-each-node-ii/) -思路: +### 思路 这道题目说是二叉树,但116题目说是完整二叉树,其实没有任何差别,一样的代码一样的逻辑一样的味道 @@ -2339,7 +2348,9 @@ public: }; ``` -Java 代码: +### 其他语言版本 + +#### Java: ```java // 二叉树之层次遍历 @@ -2377,7 +2388,7 @@ class Solution { } ``` -python代码: +#### Python: ```python # 层序遍历解法 @@ -2420,7 +2431,7 @@ class Solution: ``` -go: +#### Go: ```GO /** @@ -2459,7 +2470,7 @@ func connect(root *Node) *Node { } ``` -JavaScript: +#### JavaScript: ```javascript /** @@ -2494,7 +2505,7 @@ var connect = function(root) { }; ``` -TypeScript: +#### TypeScript: ```typescript function connect(root: Node | null): Node | null { @@ -2519,7 +2530,7 @@ function connect(root: Node | null): Node | null { }; ``` -Swift: +#### Swift: ```swift func connect(_ root: Node?) -> Node? { @@ -2551,7 +2562,7 @@ func connect(_ root: Node?) -> Node? { } ``` -Scala: +#### Scala: ```scala // 117.填充每个节点的下一个右侧节点指针II @@ -2582,7 +2593,7 @@ object Solution { } ``` -# 104.二叉树的最大深度 +## 104.二叉树的最大深度 [力扣题目链接](https://leetcode.cn/problems/maximum-depth-of-binary-tree/) @@ -2600,7 +2611,7 @@ object Solution { 返回它的最大深度 3 。 -思路: +### 思路 使用迭代法的话,使用层序遍历是最为合适的,因为最大的深度就是二叉树的层数,和层序遍历的方式极其吻合。 @@ -2635,7 +2646,9 @@ public: }; ``` -Java: +### 其他语言版本 + +#### Java: ```Java class Solution { @@ -2661,7 +2674,7 @@ class Solution { } ``` -Python: +#### Python: ```python 3 # Definition for a binary tree node. @@ -2691,7 +2704,7 @@ class Solution: ``` -Go: +#### Go: ```go /** @@ -2726,7 +2739,7 @@ func maxDepth(root *TreeNode) int { } ``` -JavaScript: +#### JavaScript: ```javascript /** @@ -2759,7 +2772,7 @@ var maxDepth = function(root) { }; ``` -TypeScript: +#### TypeScript: ```typescript function maxDepth(root: TreeNode | null): number { @@ -2779,7 +2792,7 @@ function maxDepth(root: TreeNode | null): number { }; ``` -Swift: +#### Swift: ```swift func maxDepth(_ root: TreeNode?) -> Int { @@ -2804,7 +2817,7 @@ func maxDepth(_ root: TreeNode?) -> Int { } ``` -Scala: +#### Scala: ```scala // 104.二叉树的最大深度 @@ -2829,7 +2842,7 @@ object Solution { } ``` -rust: +#### Rust: ```rust use std::cell::RefCell; @@ -2859,10 +2872,12 @@ impl Solution { } ``` -# 111.二叉树的最小深度 +## 111.二叉树的最小深度 [力扣题目链接](https://leetcode.cn/problems/minimum-depth-of-binary-tree/) +### 思路 + 相对于 104.二叉树的最大深度 ,本题还也可以使用层序遍历的方式来解决,思路是一样的。 **需要注意的是,只有当左右孩子都为空的时候,才说明遍历的最低点了。如果其中一个孩子为空则不是最低点** @@ -2895,7 +2910,9 @@ public: }; ``` -Java: +### 其他语言版本 + +#### Java: ```java class Solution { @@ -2925,9 +2942,7 @@ class Solution { } ``` - - -Python 3: +#### Python: ```python 3 # Definition for a binary tree node. @@ -2960,7 +2975,7 @@ class Solution: return depth ``` -Go: +#### Go: ```go /** @@ -2999,7 +3014,7 @@ func minDepth(root *TreeNode) int { } ``` -JavaScript: +#### JavaScript: ```javascript /** @@ -3035,7 +3050,7 @@ var minDepth = function(root) { }; ``` -TypeScript: +#### TypeScript: ```typescript function minDepth(root: TreeNode | null): number { @@ -3056,7 +3071,7 @@ function minDepth(root: TreeNode | null): number { }; ``` -Swift: +#### Swift: ```swift func minDepth(_ root: TreeNode?) -> Int { @@ -3082,7 +3097,7 @@ func minDepth(_ root: TreeNode?) -> Int { } ``` -Scala: +#### Scala: ```scala // 111.二叉树的最小深度 @@ -3108,7 +3123,7 @@ object Solution { } ``` -rust: +#### Rust: ```rust use std::cell::RefCell; @@ -3141,28 +3156,27 @@ impl Solution { } ``` -# 总结 +## 总结 二叉树的层序遍历,**就是图论中的广度优先搜索在二叉树中的应用**,需要借助队列来实现(此时又发现队列的一个应用了)。 来吧,一口气打十个: -* 102.二叉树的层序遍历 -* 107.二叉树的层次遍历II -* 199.二叉树的右视图 -* 637.二叉树的层平均值 -* 429.N叉树的层序遍历 -* 515.在每个树行中找最大值 -* 116.填充每个节点的下一个右侧节点指针 -* 117.填充每个节点的下一个右侧节点指针II -* 104.二叉树的最大深度 -* 111.二叉树的最小深度 +* [102.二叉树的层序遍历](https://leetcode.cn/problems/binary-tree-level-order-traversal/) +* [107.二叉树的层次遍历II](https://leetcode.cn/problems/binary-tree-level-order-traversal-ii/) +* [199.二叉树的右视图](https://leetcode.cn/problems/binary-tree-right-side-view/) +* [637.二叉树的层平均值](https://leetcode.cn/problems/binary-tree-right-side-view/) +* [429.N叉树的层序遍历](https://leetcode.cn/problems/n-ary-tree-level-order-traversal/) +* [515.在每个树行中找最大值](https://leetcode.cn/problems/find-largest-value-in-each-tree-row/) +* [116.填充每个节点的下一个右侧节点指针](https://leetcode.cn/problems/populating-next-right-pointers-in-each-node/) +* [117.填充每个节点的下一个右侧节点指针II](https://leetcode.cn/problems/populating-next-right-pointers-in-each-node-ii/) +* [104.二叉树的最大深度](https://leetcode.cn/problems/maximum-depth-of-binary-tree/) +* [111.二叉树的最小深度](https://leetcode.cn/problems/minimum-depth-of-binary-tree/) **致敬叶师傅!** - -

+ From 1abe3506ea6108a14d32b3176bb44674212cd9b1 Mon Sep 17 00:00:00 2001 From: jinbudaily <18336218010@163.com> Date: Fri, 21 Jul 2023 14:19:58 +0800 Subject: [PATCH 076/122] =?UTF-8?q?=E6=9B=B4=E6=96=B0=200226.=E7=BF=BB?= =?UTF-8?q?=E8=BD=AC=E4=BA=8C=E5=8F=89=E6=A0=91=20=E6=8E=92=E7=89=88?= =?UTF-8?q?=E6=A0=BC=E5=BC=8F=E4=BF=AE=E5=A4=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- problems/0226.翻转二叉树.md | 33 ++++++++++++++++++--------------- 1 file changed, 18 insertions(+), 15 deletions(-) diff --git a/problems/0226.翻转二叉树.md b/problems/0226.翻转二叉树.md index b3aea9ed..11517783 100644 --- a/problems/0226.翻转二叉树.md +++ b/problems/0226.翻转二叉树.md @@ -16,7 +16,11 @@ 这道题目背后有一个让程序员心酸的故事,听说 Homebrew的作者Max Howell,就是因为没在白板上写出翻转二叉树,最后被Google拒绝了。(真假不做判断,权当一个乐子哈) -# 题外话 +## 算法公开课 + +**[《代码随想录》算法视频公开课](https://programmercarl.com/other/gongkaike.html):[听说一位巨佬面Google被拒了,因为没写出翻转二叉树 | LeetCode:226.翻转二叉树](https://www.bilibili.com/video/BV1sP4y1f7q7),相信结合视频再看本篇题解,更有助于大家对本题的理解**。 + +## 题外话 这道题目是非常经典的题目,也是比较简单的题目(至少一看就会)。 @@ -24,9 +28,7 @@ 如果做过这道题的同学也建议认真看完,相信一定有所收获! -# 思路 - -《代码随想录》算法视频公开课:[听说一位巨佬面Google被拒了,因为没写出翻转二叉树 | LeetCode:226.翻转二叉树](https://www.bilibili.com/video/BV1sP4y1f7q7),相信结合视频在看本篇题解,更有助于大家对本题的理解。 +## 思路 我们之前介绍的都是各种方式遍历二叉树,这次要翻转了,感觉还是有点懵逼。 @@ -49,7 +51,7 @@ 那么层序遍历可以不可以呢?**依然可以的!只要把每一个节点的左右孩子翻转一下的遍历方式都是可以的!** -## 递归法 +### 递归法 对于二叉树的递归法的前中后序遍历,已经在[二叉树:前中后序递归遍历](https://programmercarl.com/二叉树的递归遍历.html)详细讲解了。 @@ -102,9 +104,9 @@ public: }; ``` -## 迭代法 +### 迭代法 -### 深度优先遍历 +#### 深度优先遍历 [二叉树:听说递归能做的,栈也能做!](https://programmercarl.com/二叉树的迭代遍历.html)中给出了前中后序迭代方式的写法,所以本题可以很轻松的写出如下迭代法的代码: @@ -163,7 +165,7 @@ public: 如果上面这个代码看不懂,回顾一下文章[二叉树:前中后序迭代方式的统一写法](https://programmercarl.com/二叉树的统一迭代法.html)。 -### 广度优先遍历 +#### 广度优先遍历 也就是层序遍历,层数遍历也是可以翻转这棵树的,因为层序遍历也可以把每个节点的左右孩子都翻转一遍,代码如下: @@ -259,7 +261,7 @@ public: ## 其他语言版本 -### Java +### Java: ```Java //DFS递归 class Solution { @@ -310,7 +312,7 @@ class Solution { } ``` -### Python +### Python: 递归法:前序遍历: ```python @@ -466,7 +468,7 @@ class Solution: ``` -### Go +### Go: 递归版本的前序遍历 ```Go @@ -575,7 +577,7 @@ func invertTree(root *TreeNode) *TreeNode { } ``` -### JavaScript +### JavaScript: 使用递归版本的前序遍历 ```javascript @@ -783,7 +785,7 @@ function invertTree(root: TreeNode | null): TreeNode | null { }; ``` -### C +### C: 递归法 ```c @@ -961,7 +963,7 @@ object Solution { } ``` -### rust +### Rust: ```rust impl Solution { @@ -991,7 +993,7 @@ impl Solution { } ``` -### C# +### C#: ```csharp //递归 @@ -1042,3 +1044,4 @@ public class Solution { + From 49a38691744fbce62c7735a722b917448ab3e4a6 Mon Sep 17 00:00:00 2001 From: jinbudaily <18336218010@163.com> Date: Fri, 21 Jul 2023 14:46:55 +0800 Subject: [PATCH 077/122] =?UTF-8?q?=E6=9B=B4=E6=96=B0=200101.=E5=AF=B9?= =?UTF-8?q?=E7=A7=B0=E4=BA=8C=E5=8F=89=E6=A0=91=20=E6=8E=92=E7=89=88?= =?UTF-8?q?=E6=A0=BC=E5=BC=8F=E4=BF=AE=E5=A4=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- problems/0101.对称二叉树.md | 39 ++++++++++++++++++++----------------- 1 file changed, 21 insertions(+), 18 deletions(-) diff --git a/problems/0101.对称二叉树.md b/problems/0101.对称二叉树.md index 4418c62d..36b39740 100644 --- a/problems/0101.对称二叉树.md +++ b/problems/0101.对称二叉树.md @@ -13,9 +13,11 @@ ![101. 对称二叉树](https://code-thinking-1253855093.file.myqcloud.com/pics/20210203144607387.png) -# 思路 +## 算法公开课 -《代码随想录》算法视频公开课:[同时操作两个二叉树 | LeetCode:101. 对称二叉树](https://www.bilibili.com/video/BV1ue4y1Y7Mf),相信结合视频在看本篇题解,更有助于大家对本题的理解。 +**[《代码随想录》算法视频公开课](https://programmercarl.com/other/gongkaike.html):[同时操作两个二叉树 | LeetCode:101. 对称二叉树](https://www.bilibili.com/video/BV1ue4y1Y7Mf), 相信结合视频再看本篇题解,更有助于大家对本题的理解**。 + +## 思路 **首先想清楚,判断对称二叉树要比较的是哪两个节点,要比较的可不是左右节点!** @@ -41,7 +43,7 @@ 那么我们先来看看递归法的代码应该怎么写。 -## 递归法 +### 递归法 递归三部曲 @@ -159,13 +161,13 @@ public: **所以建议大家做题的时候,一定要想清楚逻辑,每一步做什么。把题目所有情况想到位,相应的代码写出来之后,再去追求简洁代码的效果。** -## 迭代法 +### 迭代法 这道题目我们也可以使用迭代法,但要注意,这里的迭代法可不是前中后序的迭代写法,因为本题的本质是判断两个树是否是相互翻转的,其实已经不是所谓二叉树遍历的前中后序的关系了。 这里我们可以使用队列来比较两个树(根节点的左右子树)是否相互翻转,(**注意这不是层序遍历**) -### 使用队列 +#### 使用队列 通过队列来判断根节点的左子树和右子树的内侧和外侧是否相等,如动画所示: @@ -207,7 +209,7 @@ public: }; ``` -### 使用栈 +#### 使用栈 细心的话,其实可以发现,这个迭代法,其实是把左右两个子树要比较的元素顺序放进一个容器,然后成对成对的取出来进行比较,那么其实使用栈也是可以的。 @@ -254,12 +256,12 @@ public: 这两道题目基本和本题是一样的,只要稍加修改就可以AC。 -* 100.相同的树 -* 572.另一个树的子树 +* [100.相同的树](https://leetcode.cn/problems/same-tree/) +* [572.另一个树的子树](https://leetcode.cn/problems/subtree-of-another-tree/) -# 其他语言版本 +## 其他语言版本 -Java +### Java: ```Java /** @@ -364,7 +366,7 @@ Java ``` -Python +### Python: 递归法: ```python @@ -470,7 +472,8 @@ class Solution: return True ``` -Go +### Go: + ```go /** * Definition for a binary tree node. @@ -521,8 +524,7 @@ func isSymmetric(root *TreeNode) bool { } ``` - -JavaScript +### JavaScript: 递归判断是否为对称二叉树: ```javascript @@ -610,7 +612,7 @@ var isSymmetric = function(root) { }; ``` -TypeScript: +### TypeScript: > 递归法 @@ -679,7 +681,7 @@ function isSymmetric(root: TreeNode | null): boolean { }; ``` -Swift: +### Swift: > 递归 ```swift @@ -761,7 +763,7 @@ func isSymmetric3(_ root: TreeNode?) -> Bool { } ``` -Scala +### Scala: > 递归: ```scala @@ -835,7 +837,7 @@ object Solution { } ``` -## Rust +### Rust: 递归: ```rust @@ -900,3 +902,4 @@ impl Solution { + From 4e77ae645077ade4306bbb1ef4219bc4e41c7d29 Mon Sep 17 00:00:00 2001 From: jinbudaily <18336218010@163.com> Date: Fri, 21 Jul 2023 14:57:25 +0800 Subject: [PATCH 078/122] =?UTF-8?q?=E6=9B=B4=E6=96=B0=200104.=E4=BA=8C?= =?UTF-8?q?=E5=8F=89=E6=A0=91=E7=9A=84=E6=9C=80=E5=A4=A7=E6=B7=B1=E5=BA=A6?= =?UTF-8?q?=20=E6=8E=92=E7=89=88=E6=A0=BC=E5=BC=8F=E4=BF=AE=E5=A4=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- problems/0104.二叉树的最大深度.md | 83 +++++++++++++++++-------------- 1 file changed, 45 insertions(+), 38 deletions(-) diff --git a/problems/0104.二叉树的最大深度.md b/problems/0104.二叉树的最大深度.md index 7130867b..05044375 100644 --- a/problems/0104.二叉树的最大深度.md +++ b/problems/0104.二叉树的最大深度.md @@ -5,6 +5,7 @@

参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!

+ # 104.二叉树的最大深度 [力扣题目链接](https://leetcode.cn/problems/maximum-depth-of-binary-tree/) @@ -23,17 +24,19 @@ 返回它的最大深度 3 。 -# 思路 +## 算法公开课 + +**[《代码随想录》算法视频公开课](https://programmercarl.com/other/gongkaike.html):[二叉树的高度和深度有啥区别?究竟用什么遍历顺序?很多录友搞不懂 | 104.二叉树的最大深度](https://www.bilibili.com/video/BV1Gd4y1V75u),相信结合视频再看本篇题解,更有助于大家对本题的理解**。 + +## 思路 看完本篇可以一起做了如下两道题目: -* 104.二叉树的最大深度 -* 559.n叉树的最大深度 - -《代码随想录》算法视频公开课:[二叉树的高度和深度有啥区别?究竟用什么遍历顺序?很多录友搞不懂 | 104.二叉树的最大深度](https://www.bilibili.com/video/BV1Gd4y1V75u),相信结合视频在看本篇题解,更有助于大家对本题的理解。 +* [104.二叉树的最大深度](https://leetcode.cn/problems/maximum-depth-of-binary-tree/) +* [559.n叉树的最大深度](https://leetcode.cn/problems/maximum-depth-of-n-ary-tree/) -## 递归法 +### 递归法 本题可以使用前序(中左右),也可以使用后序遍历(左右中),使用前序求的就是深度,使用后序求的是高度。 @@ -164,7 +167,7 @@ public: }; ``` -## 迭代法 +### 迭代法 使用迭代法的话,使用层序遍历是最为合适的,因为最大的深度就是二叉树的层数,和层序遍历的方式极其吻合。 @@ -202,10 +205,11 @@ public: }; ``` - 那么我们可以顺便解决一下n叉树的最大深度问题 -# 559.n叉树的最大深度 +## 相关题目推荐 + +### 559.n叉树的最大深度 [力扣题目链接](https://leetcode.cn/problems/maximum-depth-of-n-ary-tree/) @@ -219,11 +223,11 @@ public: 我们应返回其最大深度,3。 -思路: +### 思路 依然可以提供递归法和迭代法,来解决这个问题,思路是和二叉树思路一样的,直接给出代码如下: -## 递归法 +#### 递归法 c++代码: @@ -240,7 +244,7 @@ public: } }; ``` -## 迭代法 +#### 迭代法 依然是层序遍历,代码如下: @@ -267,11 +271,11 @@ public: }; ``` -# 其他语言版本 +## 其他语言版本 -## java +### Java: -### 104.二叉树的最大深度 +104.二叉树的最大深度 ```java class solution { @@ -344,7 +348,8 @@ class solution { } ``` -### 559.n叉树的最大深度 +559.n叉树的最大深度 + ```java class Solution { /*递归法,后序遍历求root节点的高度*/ @@ -391,9 +396,9 @@ class solution { } ``` -## python +### Python : -### 104.二叉树的最大深度 +104.二叉树的最大深度 递归法: ```python @@ -448,7 +453,7 @@ class Solution: ``` -### 559.n叉树的最大深度 +559.n叉树的最大深度 递归法: ```python @@ -522,9 +527,10 @@ class Solution: return max_depth ``` +### Go: + +104.二叉树的最大深度 -## go -### 104.二叉树的最大深度 ```go /** * definition for a binary tree node. @@ -574,7 +580,7 @@ func maxdepth(root *treenode) int { ``` -### 559. n叉树的最大深度 +559. n叉树的最大深度 ```go func maxDepth(root *Node) int { @@ -598,9 +604,9 @@ func maxDepth(root *Node) int { } ``` -## javascript +### Javascript : -### 104.二叉树的最大深度 +104.二叉树的最大深度 ```javascript var maxdepth = function(root) { @@ -649,7 +655,7 @@ var maxDepth = function(root) { }; ``` -### 559.n叉树的最大深度 +559.n叉树的最大深度 N叉树的最大深度 递归写法 ```js @@ -683,9 +689,9 @@ var maxDepth = function(root) { }; ``` -## TypeScript +### TypeScript: -### 104.二叉树的最大深度 +104.二叉树的最大深度 ```typescript // 后续遍历(自下而上) @@ -728,7 +734,7 @@ function maxDepth(root: TreeNode | null): number { }; ``` -### 559.n叉树的最大深度 +559.n叉树的最大深度 ```typescript // 后续遍历(自下而上) @@ -756,9 +762,9 @@ function maxDepth(root: TreeNode | null): number { ``` -## C +### C: -### 104.二叉树的最大深度 +104.二叉树的最大深度 二叉树最大深度递归 ```c @@ -814,9 +820,9 @@ int maxDepth(struct TreeNode* root){ } ``` -## Swift +### Swift: -### 104.二叉树的最大深度 +104.二叉树的最大深度 ```swift // 递归 - 后序 @@ -856,7 +862,7 @@ func maxDepth(_ root: TreeNode?) -> Int { } ``` -### 559.n叉树的最大深度 +559.n叉树的最大深度 ```swift // 递归 @@ -893,9 +899,10 @@ func maxDepth1(_ root: Node?) -> Int { } ``` -## Scala +### Scala: + +104.二叉树的最大深度 -### 104.二叉树的最大深度 递归法: ```scala object Solution { @@ -934,7 +941,7 @@ object Solution { } ``` -### 559.n叉树的最大深度 +559.n叉树的最大深度 递归法: ```scala @@ -972,8 +979,8 @@ object Solution { } ``` -## rust -### 0104.二叉树的最大深度 +### Rust: +0104.二叉树的最大深度 递归: ```rust From 600a42730c360df82e626ce91e27efc00342b310 Mon Sep 17 00:00:00 2001 From: jinbudaily <18336218010@163.com> Date: Fri, 21 Jul 2023 15:03:31 +0800 Subject: [PATCH 079/122] =?UTF-8?q?=E6=9B=B4=E6=96=B0=200111.=E4=BA=8C?= =?UTF-8?q?=E5=8F=89=E6=A0=91=E7=9A=84=E6=9C=80=E5=B0=8F=E6=B7=B1=E5=BA=A6?= =?UTF-8?q?=20=E6=8E=92=E7=89=88=E6=A0=BC=E5=BC=8F=E4=BF=AE=E5=A4=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- problems/0111.二叉树的最小深度.md | 31 ++++++++++++++++--------------- 1 file changed, 16 insertions(+), 15 deletions(-) diff --git a/problems/0111.二叉树的最小深度.md b/problems/0111.二叉树的最小深度.md index a1fc8a93..61f9beb7 100644 --- a/problems/0111.二叉树的最小深度.md +++ b/problems/0111.二叉树的最小深度.md @@ -26,9 +26,11 @@ 返回它的最小深度 2. -# 思路 +## 算法公开课 -《代码随想录》算法视频公开课:[看起来好像做过,一写就错! | LeetCode:111.二叉树的最小深度](https://www.bilibili.com/video/BV1QD4y1B7e2),相信结合视频在看本篇题解,更有助于大家对本题的理解。 +**[《代码随想录》算法视频公开课](https://programmercarl.com/other/gongkaike.html):[看起来好像做过,一写就错! | LeetCode:111.二叉树的最小深度](https://www.bilibili.com/video/BV1QD4y1B7e2),相信结合视频再看本篇题解,更有助于大家对本题的理解**。 + +## 思路 看完了这篇[104.二叉树的最大深度](https://programmercarl.com/0104.二叉树的最大深度.html),再来看看如何求最小深度。 @@ -52,7 +54,7 @@ 什么是叶子节点,左右孩子都为空的节点才是叶子节点! -## 递归法 +### 递归法 来来来,一起递归三部曲: @@ -199,7 +201,7 @@ public: }; ``` -## 迭代法 +### 迭代法 相对于[104.二叉树的最大深度](https://programmercarl.com/0104.二叉树的最大深度.html),本题还可以使用层序遍历的方式来解决,思路是一样的。 @@ -237,10 +239,10 @@ public: ``` -# 其他语言版本 +## 其他语言版本 -## Java +### Java: ```Java class Solution { @@ -300,7 +302,7 @@ class Solution { } ``` -## Python +### Python : 递归法(版本一) @@ -400,9 +402,7 @@ class Solution: return depth ``` - - -## Go +### Go: ```go /** @@ -463,7 +463,7 @@ func minDepth(root *TreeNode) int { ``` -## JavaScript +### JavaScript: 递归法: @@ -509,7 +509,7 @@ var minDepth = function(root) { }; ``` -## TypeScript +### TypeScript: > 递归法 @@ -547,7 +547,7 @@ function minDepth(root: TreeNode | null): number { }; ``` -## Swift +### Swift: > 递归 ```Swift @@ -594,7 +594,7 @@ func minDepth(_ root: TreeNode?) -> Int { ``` -## Scala +### Scala: 递归法: ```scala @@ -633,7 +633,8 @@ object Solution { } ``` -rust: +### Rust: + ```rust impl Solution { // 递归 From 40f0e737046592e9b32075f7dad43b305158f90b Mon Sep 17 00:00:00 2001 From: jinbudaily <18336218010@163.com> Date: Fri, 21 Jul 2023 15:08:43 +0800 Subject: [PATCH 080/122] =?UTF-8?q?=E6=9B=B4=E6=96=B0=200222.=E5=AE=8C?= =?UTF-8?q?=E5=85=A8=E4=BA=8C=E5=8F=89=E6=A0=91=E7=9A=84=E8=8A=82=E7=82=B9?= =?UTF-8?q?=E4=B8=AA=E6=95=B0=20=E6=8E=92=E7=89=88=E6=A0=BC=E5=BC=8F?= =?UTF-8?q?=E4=BF=AE=E5=A4=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- problems/0222.完全二叉树的节点个数.md | 41 ++++++++++++++------------- 1 file changed, 21 insertions(+), 20 deletions(-) diff --git a/problems/0222.完全二叉树的节点个数.md b/problems/0222.完全二叉树的节点个数.md index 795a6f37..d54f9b85 100644 --- a/problems/0222.完全二叉树的节点个数.md +++ b/problems/0222.完全二叉树的节点个数.md @@ -29,14 +29,17 @@ * 0 <= Node.val <= 5 * 10^4 * 题目数据保证输入的树是 完全二叉树 +## 算法公开课 -# 思路 +**[《代码随想录》算法视频公开课](https://programmercarl.com/other/gongkaike.html):[要理解普通二叉树和完全二叉树的区别! | LeetCode:222.完全二叉树节点的数量](https://www.bilibili.com/video/BV1eW4y1B7pD),相信结合视频再看本篇题解,更有助于大家对本题的理解**。 + + +## 思路 -《代码随想录》算法视频公开课:[要理解普通二叉树和完全二叉树的区别! | LeetCode:222.完全二叉树节点的数量](https://www.bilibili.com/video/BV1eW4y1B7pD),相信结合视频在看本篇题解,更有助于大家对本题的理解。 本篇给出按照普通二叉树的求法以及利用完全二叉树性质的求法。 -## 普通二叉树 +### 普通二叉树 首先按照普通二叉树的逻辑来求。 @@ -44,7 +47,7 @@ 递归遍历的顺序依然是后序(左右中)。 -### 递归 +#### 递归 如果对求二叉树深度还不熟悉的话,看这篇:[二叉树:看看这些树的最大深度](https://programmercarl.com/0104.二叉树的最大深度.html)。 @@ -112,7 +115,7 @@ public: **网上基本都是这个精简的代码版本,其实不建议大家照着这个来写,代码确实精简,但隐藏了一些内容,连遍历的顺序都看不出来,所以初学者建议学习版本一的代码,稳稳的打基础**。 -### 迭代法 +#### 迭代 如果对求二叉树层序遍历还不熟悉的话,看这篇:[二叉树:层序遍历登场!](https://programmercarl.com/0102.二叉树的层序遍历.html)。 @@ -142,7 +145,7 @@ public: * 时间复杂度:O(n) * 空间复杂度:O(n) -## 完全二叉树 +### 完全二叉树 以上方法都是按照普通二叉树来做的,对于完全二叉树特性不了解的同学可以看这篇 [关于二叉树,你该了解这些!](https://programmercarl.com/二叉树理论基础.html),这篇详细介绍了各种二叉树的特性。 @@ -249,9 +252,9 @@ public: * 时间复杂度:O(log n × log n) * 空间复杂度:O(log n) -# 其他语言版本 +## 其他语言版本 -## Java +### Java: ```java class Solution { // 通用递归解法 @@ -312,7 +315,7 @@ class Solution { } ``` -## Python +### Python: 递归法: ```python @@ -408,7 +411,7 @@ class Solution: # 利用完全二叉树特性 return 1+self.countNodes(root.left)+self.countNodes(root.right) ``` -## Go +### Go: 递归版本 @@ -488,9 +491,7 @@ func countNodes(root *TreeNode) int { } ``` - - -## JavaScript: +### JavaScript: 递归版本 ```javascript @@ -559,7 +560,7 @@ var countNodes = function(root) { }; ``` -## TypeScrpt: +### TypeScrpt: > 递归法 @@ -614,7 +615,7 @@ function countNodes(root: TreeNode | null): number { }; ``` -## C: +### C: 递归法 ```c @@ -690,7 +691,7 @@ int countNodes(struct TreeNode* root){ } ``` -## Swift: +### Swift: > 递归 ```swift @@ -758,7 +759,7 @@ func countNodes(_ root: TreeNode?) -> Int { } ``` -## Scala +### Scala: 递归: ```scala @@ -821,9 +822,9 @@ object Solution { } ``` -rust: +### Rust: -// 递归 +递归 ```rust use std::cell::RefCell; use std::rc::Rc; @@ -838,7 +839,7 @@ impl Solution { } ``` -// 迭代 +迭代 ```rust use std::rc::Rc; use std::cell::RefCell; From ff6ff4adb86b80bc748c34f5f1c679f08d9c1ec2 Mon Sep 17 00:00:00 2001 From: jinbudaily <18336218010@163.com> Date: Fri, 21 Jul 2023 15:12:28 +0800 Subject: [PATCH 081/122] =?UTF-8?q?=E6=9B=B4=E6=96=B0=200110.=E5=B9=B3?= =?UTF-8?q?=E8=A1=A1=E4=BA=8C=E5=8F=89=E6=A0=91=20=E6=8E=92=E7=89=88?= =?UTF-8?q?=E6=A0=BC=E5=BC=8F=E4=BF=AE=E5=A4=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- problems/0110.平衡二叉树.md | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/problems/0110.平衡二叉树.md b/problems/0110.平衡二叉树.md index e10a612a..c7df9c8f 100644 --- a/problems/0110.平衡二叉树.md +++ b/problems/0110.平衡二叉树.md @@ -33,8 +33,9 @@ 返回 false 。 +## 算法公开课 -**《代码随想录》算法视频公开课:[后序遍历求高度,高度判断是否平衡 | LeetCode:110.平衡二叉树](https://www.bilibili.com/video/BV1Ug411S7my),相信结合视频在看本篇题解,更有助于大家对本题的理解**。 +**[《代码随想录》算法视频公开课](https://programmercarl.com/other/gongkaike.html):[后序遍历求高度,高度判断是否平衡 | LeetCode:110.平衡二叉树](https://www.bilibili.com/video/BV1Ug411S7my),相信结合视频在看本篇题解,更有助于大家对本题的理解**。 ## 题外话 @@ -357,7 +358,7 @@ public: ## 其他语言版本 -### Java +### Java: ```Java class Solution { @@ -498,7 +499,7 @@ class Solution { } ``` -### Python +### Python: 递归法: @@ -620,7 +621,7 @@ class Solution: height_map[real_node] = 1 + max(left, right) return True ``` -### Go +### Go: ```Go func isBalanced(root *TreeNode) bool { @@ -652,7 +653,7 @@ func max(a, b int) int { } ``` -### JavaScript +### JavaScript: 递归法: @@ -723,7 +724,7 @@ var isBalanced = function (root) { }; ``` -### TypeScript +### TypeScript: ```typescript // 递归法 @@ -741,7 +742,7 @@ function isBalanced(root: TreeNode | null): boolean { }; ``` -### C +### C: 递归法: @@ -876,7 +877,7 @@ func getHeight(_ root: TreeNode?) -> Int { } ``` -### rust +### Rust: 递归 @@ -912,3 +913,4 @@ impl Solution { + From 95b5bb195d5af819f553cafaede57fd4c990a96d Mon Sep 17 00:00:00 2001 From: jinbudaily <18336218010@163.com> Date: Fri, 21 Jul 2023 15:18:37 +0800 Subject: [PATCH 082/122] =?UTF-8?q?0257.=E4=BA=8C=E5=8F=89=E6=A0=91?= =?UTF-8?q?=E7=9A=84=E6=89=80=E6=9C=89=E8=B7=AF=E5=BE=84=20=E6=8E=92?= =?UTF-8?q?=E7=89=88=E6=A0=BC=E5=BC=8F=E4=BF=AE=E5=A4=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- problems/0257.二叉树的所有路径.md | 43 ++++++++++++++----------------- 1 file changed, 20 insertions(+), 23 deletions(-) diff --git a/problems/0257.二叉树的所有路径.md b/problems/0257.二叉树的所有路径.md index 06153507..44c0fd85 100644 --- a/problems/0257.二叉树的所有路径.md +++ b/problems/0257.二叉树的所有路径.md @@ -18,9 +18,11 @@ 示例: ![257.二叉树的所有路径1](https://code-thinking-1253855093.file.myqcloud.com/pics/2021020415161576.png) -# 思路 +## 算法公开课 -**《代码随想录》算法视频公开课:[递归中带着回溯,你感受到了没?| LeetCode:257. 二叉树的所有路径](https://www.bilibili.com/video/BV1ZG411G7Dh),相信结合视频在看本篇题解,更有助于大家对本题的理解**。 +**[《代码随想录》算法视频公开课](https://programmercarl.com/other/gongkaike.html)::[递归中带着回溯,你感受到了没?| LeetCode:257. 二叉树的所有路径](https://www.bilibili.com/video/BV1ZG411G7Dh),相信结合视频在看本篇题解,更有助于大家对本题的理解**。 + +## 思路 这道题目要求从根节点到叶子的路径,所以需要前序遍历,这样才方便让父节点指向孩子节点,找到对应的路径。 @@ -32,7 +34,7 @@ 我们先使用递归的方式,来做前序遍历。**要知道递归和回溯就是一家的,本题也需要回溯。** -## 递归 +### 递归 1. 递归函数参数以及返回值 @@ -305,7 +307,7 @@ public: **综合以上,第二种递归的代码虽然精简但把很多重要的点隐藏在了代码细节里,第一种递归写法虽然代码多一些,但是把每一个逻辑处理都完整的展现出来了。** -## 拓展 +### 拓展 这里讲解本题解的写法逻辑以及一些更具体的细节,下面的讲解中,涉及到C++语法特性,如果不是C++的录友,就可以不看了,避免越看越晕。 @@ -328,7 +330,7 @@ public: 所以,第一个代码版本中,我才使用 vector 类型的path,这样方便给大家演示代码中回溯的操作。 vector类型的path,不管 每次 路径收集的数字是几位数,总之一定是int,所以就一次 pop_back就可以。 -## 迭代法 +### 迭代法 至于非递归的方式,我们可以依然可以使用前序遍历的迭代方式来模拟遍历路径的过程,对该迭代方式不了解的同学,可以看文章[二叉树:听说递归能做的,栈也能做!](https://programmercarl.com/二叉树的迭代遍历.html)和[二叉树:前中后序迭代方式统一写法](https://programmercarl.com/二叉树的统一迭代法.html)。 @@ -368,7 +370,7 @@ public: ``` 当然,使用java的同学,可以直接定义一个成员变量为object的栈`Stack stack = new Stack<>();`,这样就不用定义两个栈了,都放到一个栈里就可以了。 -# 总结 +## 总结 **本文我们开始初步涉及到了回溯,很多同学过了这道题目,可能都不知道自己其实使用了回溯,回溯和递归都是相伴相生的。** @@ -380,13 +382,9 @@ public: 对于本题充分了解递归与回溯的过程之后,有精力的同学可以再去实现迭代法。 +## 其他语言版本 - - - -# 其他语言版本 - -## Java: +### Java: ```Java //解法一 @@ -492,9 +490,9 @@ class Solution { } ``` --- -## Python: - - +### Python: + + 递归法+回溯 ```Python # Definition for a binary tree node. @@ -552,7 +550,7 @@ class Solution: self.traversal(cur.right, path[:], result) ``` - + 递归法+隐形回溯(版本二) ```Python # Definition for a binary tree node. @@ -610,7 +608,7 @@ class Solution: --- -## Go: +### Go: 递归法: @@ -672,7 +670,7 @@ func binaryTreePaths(root *TreeNode) []string { ``` --- -## JavaScript: +### JavaScript: 递归法: @@ -725,7 +723,7 @@ var binaryTreePaths = function(root) { }; ``` -## TypeScript: +### TypeScript: > 递归法 @@ -779,7 +777,7 @@ function binaryTreePaths(root: TreeNode | null): string[] { }; ``` -## Swift: +### Swift: > 递归/回溯 ```swift @@ -846,7 +844,7 @@ func binaryTreePaths(_ root: TreeNode?) -> [String] { } ``` -## Scala: +### Scala: 递归: ```scala @@ -876,7 +874,7 @@ object Solution { } ``` -rust: +### Rust: ```rust // 递归 @@ -907,4 +905,3 @@ impl Solution { - From a9039c0d2dd2c625c98009998677b20089b46524 Mon Sep 17 00:00:00 2001 From: jinbudaily <18336218010@163.com> Date: Fri, 21 Jul 2023 17:39:36 +0800 Subject: [PATCH 083/122] =?UTF-8?q?=E6=9B=B4=E6=96=B0=20404.=E5=B7=A6?= =?UTF-8?q?=E5=8F=B6=E5=AD=90=E4=B9=8B=E5=92=8C=20=E6=8E=92=E7=89=88?= =?UTF-8?q?=E6=A0=BC=E5=BC=8F=E4=BF=AE=E5=A4=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- problems/0404.左叶子之和.md | 29 +++++++++++++++-------------- 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/problems/0404.左叶子之和.md b/problems/0404.左叶子之和.md index aa2868df..c1ad602d 100644 --- a/problems/0404.左叶子之和.md +++ b/problems/0404.左叶子之和.md @@ -16,9 +16,9 @@ ![404.左叶子之和1](https://code-thinking-1253855093.file.myqcloud.com/pics/20210204151927654.png) -## 视频讲解 +## 算法公开课 -**《代码随想录》算法视频公开课:[二叉树的题目中,总有一些规则让你找不到北 | LeetCode:404.左叶子之和](https://www.bilibili.com/video/BV1GY4y1K7z8),相信结合视频在看本篇题解,更有助于大家对本题的理解**。 +**[《代码随想录》算法视频公开课](https://programmercarl.com/other/gongkaike.html)::[二叉树的题目中,总有一些规则让你找不到北 | LeetCode:404.左叶子之和](https://www.bilibili.com/video/BV1GY4y1K7z8),相信结合视频在看本篇题解,更有助于大家对本题的理解**。 ## 思路 @@ -48,7 +48,7 @@ if (node->left != NULL && node->left->left == NULL && node->left->right == NULL) } ``` -## 递归法 +### 递归法 递归的遍历顺序为后序遍历(左右中),是因为要通过递归函数的返回值来累加求取左叶子数值之和。 @@ -131,11 +131,11 @@ public: return leftValue + sumOfLeftLeaves(root->left) + sumOfLeftLeaves(root->right); } }; -``` +``` 精简之后的代码其实看不出来用的是什么遍历方式了,对于算法初学者以上根据第一个版本来学习。 -## 迭代法 +### 迭代法 本题迭代法使用前中后序都是可以的,只要把左叶子节点统计出来,就可以了,那么参考文章 [二叉树:听说递归能做的,栈也能做!](https://programmercarl.com/二叉树的迭代遍历.html)和[二叉树:迭代法统一写法](https://programmercarl.com/二叉树的统一迭代法.html)中的写法,可以写出一个前序遍历的迭代法。 @@ -177,7 +177,7 @@ public: ## 其他语言版本 -### Java +### Java: **递归** @@ -246,7 +246,7 @@ class Solution { ``` -### Python +### Python: 递归 ```python # Definition for a binary tree node. @@ -316,7 +316,7 @@ class Solution: ``` -### Go +### Go: **递归法** @@ -368,7 +368,7 @@ func sumOfLeftLeaves(root *TreeNode) int { ``` -### JavaScript +### JavaScript: **递归法** @@ -417,7 +417,7 @@ var sumOfLeftLeaves = function(root) { }; ``` -### TypeScript +### TypeScript: > 递归法 @@ -462,7 +462,7 @@ function sumOfLeftLeaves(root: TreeNode | null): number { }; ``` -### Swift +### Swift: **递归法** ```swift @@ -511,7 +511,7 @@ func sumOfLeftLeaves(_ root: TreeNode?) -> Int { } ``` -### C +### C: 递归法: ```c int sumOfLeftLeaves(struct TreeNode* root){ @@ -561,7 +561,7 @@ int sumOfLeftLeaves(struct TreeNode* root){ } ``` -### Scala +### Scala: **递归:** ```scala @@ -600,7 +600,7 @@ object Solution { } ``` -### Rust +### Rust: **递归** @@ -656,3 +656,4 @@ impl Solution { + From f3a370113058a82be88164ddeabf5443f82f62a0 Mon Sep 17 00:00:00 2001 From: jinbudaily <18336218010@163.com> Date: Fri, 21 Jul 2023 17:41:28 +0800 Subject: [PATCH 084/122] =?UTF-8?q?=E6=9B=B4=E6=96=B0=20513.=E6=89=BE?= =?UTF-8?q?=E6=A0=91=E5=B7=A6=E4=B8=8B=E8=A7=92=E7=9A=84=E5=80=BC=20?= =?UTF-8?q?=E6=8E=92=E7=89=88=E6=A0=BC=E5=BC=8F=E4=BF=AE=E5=A4=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- problems/0513.找树左下角的值.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/problems/0513.找树左下角的值.md b/problems/0513.找树左下角的值.md index 743b0df9..7ef934cc 100644 --- a/problems/0513.找树左下角的值.md +++ b/problems/0513.找树左下角的值.md @@ -20,9 +20,9 @@ ![513.找树左下角的值1](https://code-thinking-1253855093.file.myqcloud.com/pics/20210204153017586.png) -## 视频讲解 +## 算法公开课 -**《代码随想录》算法视频公开课:[怎么找二叉树的左下角? 递归中又带回溯了,怎么办?| LeetCode:513.找二叉树左下角的值](https://www.bilibili.com/video/BV1424y1Z7pn),相信结合视频在看本篇题解,更有助于大家对本题的理解**。 +**[《代码随想录》算法视频公开课](https://programmercarl.com/other/gongkaike.html):[怎么找二叉树的左下角? 递归中又带回溯了,怎么办?| LeetCode:513.找二叉树左下角的值](https://www.bilibili.com/video/BV1424y1Z7pn),相信结合视频在看本篇题解,更有助于大家对本题的理解**。 ## 思路 @@ -614,7 +614,7 @@ object Solution { } ``` -### rust +### Rust **层序遍历** @@ -689,3 +689,4 @@ impl Solution { + From bf6c4e7f7b3c8f118960362ab735f8e4977e0e58 Mon Sep 17 00:00:00 2001 From: jinbudaily <18336218010@163.com> Date: Fri, 21 Jul 2023 17:53:29 +0800 Subject: [PATCH 085/122] =?UTF-8?q?=E6=9B=B4=E6=96=B0=200112.=E8=B7=AF?= =?UTF-8?q?=E5=BE=84=E6=80=BB=E5=92=8C=20=E6=8E=92=E7=89=88=E6=A0=BC?= =?UTF-8?q?=E5=BC=8F=E4=BF=AE=E5=A4=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- problems/0112.路径总和.md | 75 ++++++++++++++++++++------------------- 1 file changed, 39 insertions(+), 36 deletions(-) diff --git a/problems/0112.路径总和.md b/problems/0112.路径总和.md index 39285a3b..240462b6 100644 --- a/problems/0112.路径总和.md +++ b/problems/0112.路径总和.md @@ -21,9 +21,9 @@ 返回 true, 因为存在目标和为 22 的根节点到叶子节点的路径 5->4->11->2。 -## 视频讲解 +## 算法公开课 -**《代码随想录》算法视频公开课:[拿不准的遍历顺序,搞不清的回溯过程,我太难了! | LeetCode:112. 路径总和](https://www.bilibili.com/video/BV19t4y1L7CR),相信结合视频在看本篇题解,更有助于大家对本题的理解**。 +**[《代码随想录》算法视频公开课](https://programmercarl.com/other/gongkaike.html):[拿不准的遍历顺序,搞不清的回溯过程,我太难了! | LeetCode:112. 路径总和](https://www.bilibili.com/video/BV19t4y1L7CR),相信结合视频在看本篇题解,更有助于大家对本题的理解**。 ## 思路 @@ -32,8 +32,8 @@ 那么接下来我通过详细讲解如下两道题,来回答这个问题: -* 112.路径总和 -* 113.路径总和ii +* [112.路径总和](https://leetcode.cn/problems/path-sum/) +* [113.路径总和ii](https://leetcode.cn/problems/path-sum-ii/) 这道题我们要遍历从根节点到叶子节点的路径看看总和是不是目标和。 @@ -218,7 +218,9 @@ public: 如果大家完全理解了本题的递归方法之后,就可以顺便把leetcode上113. 路径总和ii做了。 -# 113. 路径总和ii +## 相关题目推荐 + +### 113. 路径总和ii [力扣题目链接](https://leetcode.cn/problems/path-sum-ii/) @@ -232,7 +234,7 @@ public: ![113.路径总和ii1.png](https://code-thinking-1253855093.file.myqcloud.com/pics/20210203160854654.png) -## 思路 +### 思路 113.路径总和ii要遍历整个树,找到所有路径,**所以递归函数不要返回值!** @@ -289,7 +291,7 @@ public: 至于113. 路径总和ii 的迭代法我并没有写,用迭代方式记录所有路径比较麻烦,也没有必要,如果大家感兴趣的话,可以再深入研究研究。 -## 总结 +### 总结 本篇通过leetcode上112. 路径总和 和 113. 路径总和ii 详细的讲解了 递归函数什么时候需要返回值,什么不需要返回值。 @@ -300,11 +302,11 @@ public: -# 其他语言版本 +## 其他语言版本 -## java +### Java -### 0112.路径总和 +#### 0112.路径总和 ```java class solution { @@ -422,7 +424,7 @@ class solution { } ``` -### 0113.路径总和-ii +#### 0113.路径总和-ii ```java class solution { @@ -529,9 +531,9 @@ class Solution { } ``` -## python +### Python -### 0112.路径总和 +#### 0112.路径总和 (版本一) 递归 ```python @@ -618,7 +620,7 @@ class Solution: -### 0113.路径总和-ii +#### 0113.路径总和-ii (版本一) 递归 ```python @@ -719,9 +721,9 @@ class Solution: ``` -## go +### Go -### 112. 路径总和 +#### 112. 路径总和 ```go //递归法 @@ -746,7 +748,7 @@ func hasPathSum(root *TreeNode, targetSum int) bool { } ``` -### 113. 路径总和 II +#### 113. 路径总和 II ```go /** @@ -786,9 +788,9 @@ func traverse(node *TreeNode, result *[][]int, currPath *[]int, targetSum int) { } ``` -## javascript +### Javascript -### 0112.路径总和 +#### 0112.路径总和 **递归** @@ -852,7 +854,7 @@ let hasPathSum = function(root, targetSum) { }; ``` -### 0113.路径总和-ii +#### 0113.路径总和-ii **递归** @@ -950,9 +952,9 @@ let pathSum = function(root, targetSum) { }; ``` -## TypeScript +### TypeScript -### 0112.路径总和 +#### 0112.路径总和 **递归法:** @@ -1034,7 +1036,7 @@ function hasPathSum(root: TreeNode | null, targetSum: number): boolean { }; ``` -### 0112.路径总和 ii +#### 0112.路径总和 ii **递归法:** @@ -1070,9 +1072,9 @@ function pathSum(root: TreeNode | null, targetSum: number): number[][] { }; ``` -## Swift +### Swift -### 0112.路径总和 +#### 0112.路径总和 **递归** @@ -1141,7 +1143,7 @@ func hasPathSum(_ root: TreeNode?, _ targetSum: Int) -> Bool { } ``` -### 0113.路径总和 II +#### 0113.路径总和 II **递归** @@ -1192,10 +1194,10 @@ func traversal(_ cur: TreeNode?, count: Int) { } ``` -## C +### C -> 0112.路径总和 -> 递归法: +#### 0112.路径总和 +递归法: ```c bool hasPathSum(struct TreeNode* root, int targetSum){ @@ -1252,7 +1254,7 @@ bool hasPathSum(struct TreeNode* root, int targetSum){ } ``` -> 0113.路径总和 II +#### 0113.路径总和 II ```c int** ret; @@ -1317,9 +1319,9 @@ int** pathSum(struct TreeNode* root, int targetSum, int* returnSize, int** retur } ``` -## Scala +### Scala -### 0112.路径总和 +#### 0112.路径总和 **递归:** @@ -1369,7 +1371,7 @@ object Solution { } ``` -### 0113.路径总和 II +#### 0113.路径总和 II **递归:** @@ -1405,9 +1407,9 @@ object Solution { } ``` -## rust +### Rust -### 112.路径总和.md +#### 0112.路径总和 递归: @@ -1461,7 +1463,7 @@ impl Solution { } ``` -### 113.路径总和-ii +#### 0113.路径总和-ii ```rust impl Solution { @@ -1514,3 +1516,4 @@ impl Solution { + From fe9323900758c0f056299728d1551ab57d1efab3 Mon Sep 17 00:00:00 2001 From: jinbudaily <18336218010@163.com> Date: Fri, 21 Jul 2023 18:00:07 +0800 Subject: [PATCH 086/122] =?UTF-8?q?=E6=9B=B4=E6=96=B0=200106.=E4=BB=8E?= =?UTF-8?q?=E4=B8=AD=E5=BA=8F=E4=B8=8E=E5=90=8E=E5=BA=8F=E9=81=8D=E5=8E=86?= =?UTF-8?q?=E5=BA=8F=E5=88=97=E6=9E=84=E9=80=A0=E4=BA=8C=E5=8F=89=E6=A0=91?= =?UTF-8?q?=20=E6=8E=92=E7=89=88=E6=A0=BC=E5=BC=8F=E4=BF=AE=E5=A4=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../0106.从中序与后序遍历序列构造二叉树.md | 40 +++++++++---------- problems/0112.路径总和.md | 38 +++++++++--------- 2 files changed, 37 insertions(+), 41 deletions(-) diff --git a/problems/0106.从中序与后序遍历序列构造二叉树.md b/problems/0106.从中序与后序遍历序列构造二叉树.md index a0bab999..0144fc5c 100644 --- a/problems/0106.从中序与后序遍历序列构造二叉树.md +++ b/problems/0106.从中序与后序遍历序列构造二叉树.md @@ -29,9 +29,9 @@ ![106. 从中序与后序遍历序列构造二叉树1](https://code-thinking-1253855093.file.myqcloud.com/pics/20210203154316774.png) -# 视频讲解 +## 算法公开课 -**《代码随想录》算法视频公开课:[坑很多!来看看你掉过几次坑 | LeetCode:106.从中序与后序遍历序列构造二叉树](https://www.bilibili.com/video/BV1vW4y1i7dn),相信结合视频在看本篇题解,更有助于大家对本题的理解**。 +**[《代码随想录》算法视频公开课](https://programmercarl.com/other/gongkaike.html):[坑很多!来看看你掉过几次坑 | LeetCode:106.从中序与后序遍历序列构造二叉树](https://www.bilibili.com/video/BV1vW4y1i7dn),相信结合视频在看本篇题解,更有助于大家对本题的理解**。 ## 思路 @@ -158,8 +158,6 @@ root->right = traversal(rightInorder, rightPostorder); 完整代码如下: -### C++完整代码 - ```CPP class Solution { private: @@ -281,8 +279,6 @@ public: 下面给出用下标索引写出的代码版本:(思路是一样的,只不过不用重复定义vector了,每次用下标索引来分割) -### C++优化版本 - ```CPP class Solution { private: @@ -400,8 +396,9 @@ public: }; ``` +## 相关题目推荐 -# 105.从前序与中序遍历序列构造二叉树 +### 105.从前序与中序遍历序列构造二叉树 [力扣题目链接](https://leetcode.cn/problems/construct-binary-tree-from-preorder-and-inorder-traversal/) @@ -418,7 +415,7 @@ public: ![105. 从前序与中序遍历序列构造二叉树](https://code-thinking-1253855093.file.myqcloud.com/pics/20210203154626672.png) -## 思路 +### 思路 本题和106是一样的道理。 @@ -547,7 +544,7 @@ public: }; ``` -# 思考题 +## 思考题 前序和中序可以唯一确定一棵二叉树。 @@ -569,7 +566,7 @@ tree2 的前序遍历是[1 2 3], 后序遍历是[3 2 1]。 所以前序和后序不能唯一确定一棵二叉树! -# 总结 +## 总结 之前我们讲的二叉树题目都是各种遍历二叉树,这次开始构造二叉树了,思路其实比较简单,但是真正代码实现出来并不容易。 @@ -585,9 +582,9 @@ tree2 的前序遍历是[1 2 3], 后序遍历是[3 2 1]。 -# 其他语言版本 +## 其他语言版本 -## Java +### Java 106.从中序与后序遍历序列构造二叉树 @@ -688,7 +685,7 @@ class Solution { } ``` -## Python +### Python 105.从前序与中序遍历序列构造二叉树 @@ -754,7 +751,7 @@ class Solution: return root ``` -## Go +### Go 106 从中序与后序遍历序列构造二叉树 @@ -833,9 +830,7 @@ func build(pre []int, in []int, root int, l, r int) *TreeNode { ``` - - -## JavaScript +### JavaScript ```javascript var buildTree = function(inorder, postorder) { @@ -863,7 +858,7 @@ var buildTree = function(preorder, inorder) { }; ``` -## TypeScript +### TypeScript > 106.从中序与后序遍历序列构造二叉树 @@ -969,7 +964,7 @@ function buildTree(preorder: number[], inorder: number[]): TreeNode | null { }; ``` -## C +### C 106 从中序与后序遍历序列构造二叉树 @@ -1047,7 +1042,7 @@ struct TreeNode* buildTree(int* preorder, int preorderSize, int* inorder, int in } ``` -## Swift +### Swift 105 从前序与中序遍历序列构造二叉树 @@ -1140,7 +1135,7 @@ class Solution_0106 { } ``` -## Scala +### Scala 106 从中序与后序遍历序列构造二叉树 @@ -1188,7 +1183,7 @@ object Solution { } ``` -## rust +### Rust 106 从中序与后序遍历序列构造二叉树 @@ -1238,3 +1233,4 @@ impl Solution { + diff --git a/problems/0112.路径总和.md b/problems/0112.路径总和.md index 240462b6..be03f719 100644 --- a/problems/0112.路径总和.md +++ b/problems/0112.路径总和.md @@ -306,7 +306,7 @@ public: ### Java -#### 0112.路径总和 +0112.路径总和 ```java class solution { @@ -424,7 +424,7 @@ class solution { } ``` -#### 0113.路径总和-ii +0113.路径总和-ii ```java class solution { @@ -533,7 +533,7 @@ class Solution { ### Python -#### 0112.路径总和 +0112.路径总和 (版本一) 递归 ```python @@ -620,7 +620,7 @@ class Solution: -#### 0113.路径总和-ii +0113.路径总和-ii (版本一) 递归 ```python @@ -723,7 +723,7 @@ class Solution: ``` ### Go -#### 112. 路径总和 +112. 路径总和 ```go //递归法 @@ -748,7 +748,7 @@ func hasPathSum(root *TreeNode, targetSum int) bool { } ``` -#### 113. 路径总和 II +113. 路径总和 II ```go /** @@ -790,7 +790,7 @@ func traverse(node *TreeNode, result *[][]int, currPath *[]int, targetSum int) { ### Javascript -#### 0112.路径总和 +0112.路径总和 **递归** @@ -854,7 +854,7 @@ let hasPathSum = function(root, targetSum) { }; ``` -#### 0113.路径总和-ii +0113.路径总和-ii **递归** @@ -954,7 +954,7 @@ let pathSum = function(root, targetSum) { ### TypeScript -#### 0112.路径总和 +0112.路径总和 **递归法:** @@ -1036,7 +1036,7 @@ function hasPathSum(root: TreeNode | null, targetSum: number): boolean { }; ``` -#### 0112.路径总和 ii +0112.路径总和 ii **递归法:** @@ -1074,7 +1074,7 @@ function pathSum(root: TreeNode | null, targetSum: number): number[][] { ### Swift -#### 0112.路径总和 +0112.路径总和 **递归** @@ -1143,7 +1143,7 @@ func hasPathSum(_ root: TreeNode?, _ targetSum: Int) -> Bool { } ``` -#### 0113.路径总和 II +0113.路径总和 II **递归** @@ -1196,7 +1196,8 @@ func traversal(_ cur: TreeNode?, count: Int) { ### C -#### 0112.路径总和 +0112.路径总和 + 递归法: ```c @@ -1254,7 +1255,7 @@ bool hasPathSum(struct TreeNode* root, int targetSum){ } ``` -#### 0113.路径总和 II +0113.路径总和 II ```c int** ret; @@ -1321,7 +1322,7 @@ int** pathSum(struct TreeNode* root, int targetSum, int* returnSize, int** retur ### Scala -#### 0112.路径总和 +0112.路径总和 **递归:** @@ -1371,7 +1372,7 @@ object Solution { } ``` -#### 0113.路径总和 II +0113.路径总和 II **递归:** @@ -1409,7 +1410,7 @@ object Solution { ### Rust -#### 0112.路径总和 +0112.路径总和 递归: @@ -1463,7 +1464,7 @@ impl Solution { } ``` -#### 0113.路径总和-ii +0113.路径总和-ii ```rust impl Solution { @@ -1516,4 +1517,3 @@ impl Solution { - From b4eefe985945fdeaf4e1e34ebbc90b74258d43e2 Mon Sep 17 00:00:00 2001 From: jinbudaily <18336218010@163.com> Date: Fri, 21 Jul 2023 18:54:16 +0800 Subject: [PATCH 087/122] =?UTF-8?q?=E6=9B=B4=E6=96=B0=200654.=E6=9C=80?= =?UTF-8?q?=E5=A4=A7=E4=BA=8C=E5=8F=89=E6=A0=91=20=E6=8E=92=E7=89=88?= =?UTF-8?q?=E6=A0=BC=E5=BC=8F=E4=BF=AE=E5=A4=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- problems/0654.最大二叉树.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/problems/0654.最大二叉树.md b/problems/0654.最大二叉树.md index 33a9176e..77d7980f 100644 --- a/problems/0654.最大二叉树.md +++ b/problems/0654.最大二叉树.md @@ -25,9 +25,9 @@ 给定的数组的大小在 [1, 1000] 之间。 -## 视频讲解 +## 算法公开课 -**《代码随想录》算法视频公开课:[又是构造二叉树,又有很多坑!| LeetCode:654.最大二叉树](https://www.bilibili.com/video/BV1MG411G7ox),相信结合视频在看本篇题解,更有助于大家对本题的理解**。 +**[《代码随想录》算法视频公开课](https://programmercarl.com/other/gongkaike.html):[又是构造二叉树,又有很多坑!| LeetCode:654.最大二叉树](https://www.bilibili.com/video/BV1MG411G7ox),相信结合视频在看本篇题解,更有助于大家对本题的理解**。 ## 思路 @@ -310,7 +310,7 @@ class Solution: def constructMaximumBinaryTree(self, nums: List[int]) -> TreeNode: return self.traversal(nums, 0, len(nums)) - ``` +``` (版本三) 使用切片 @@ -587,3 +587,4 @@ impl Solution { + From eadc704c38816cfdb7f21f22d3489dc38ea5aecc Mon Sep 17 00:00:00 2001 From: jinbudaily <18336218010@163.com> Date: Fri, 21 Jul 2023 20:18:53 +0800 Subject: [PATCH 088/122] =?UTF-8?q?=E6=9B=B4=E6=96=B0=200617.=E5=90=88?= =?UTF-8?q?=E5=B9=B6=E4=BA=8C=E5=8F=89=E6=A0=91=20=E6=8E=92=E7=89=88?= =?UTF-8?q?=E6=A0=BC=E5=BC=8F=E4=BF=AE=E5=A4=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- problems/0617.合并二叉树.md | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/problems/0617.合并二叉树.md b/problems/0617.合并二叉树.md index 18a245c4..44092aae 100644 --- a/problems/0617.合并二叉树.md +++ b/problems/0617.合并二叉树.md @@ -19,9 +19,9 @@ 注意: 合并必须从两个树的根节点开始。 -# 视频讲解 +# 算法公开课 -**《代码随想录》算法视频公开课:[一起操作两个二叉树?有点懵!| LeetCode:617.合并二叉树](https://www.bilibili.com/video/BV1m14y1Y7JK),相信结合视频在看本篇题解,更有助于大家对本题的理解**。 +**[《代码随想录》算法视频公开课](https://programmercarl.com/other/gongkaike.html):[一起操作两个二叉树?有点懵!| LeetCode:617.合并二叉树](https://www.bilibili.com/video/BV1m14y1Y7JK),相信结合视频在看本篇题解,更有助于大家对本题的理解**。 ## 思路 @@ -164,7 +164,7 @@ public: }; ``` -## 迭代法 +### 迭代法 使用迭代法,如何同时处理两棵树呢? @@ -716,7 +716,7 @@ object Solution { } ``` -### rust +### Rust 递归: @@ -793,4 +793,3 @@ impl Solution { - From ac239bc437cfa8de6859fa8a98cc04b9cf6d1d4c Mon Sep 17 00:00:00 2001 From: jinbudaily <18336218010@163.com> Date: Fri, 21 Jul 2023 20:20:25 +0800 Subject: [PATCH 089/122] =?UTF-8?q?=E6=9B=B4=E6=96=B0=200700.=E4=BA=8C?= =?UTF-8?q?=E5=8F=89=E6=90=9C=E7=B4=A2=E6=A0=91=E4=B8=AD=E7=9A=84=E6=90=9C?= =?UTF-8?q?=E7=B4=A2=20=E6=8E=92=E7=89=88=E6=A0=BC=E5=BC=8F=E4=BF=AE?= =?UTF-8?q?=E5=A4=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- problems/0700.二叉搜索树中的搜索.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/problems/0700.二叉搜索树中的搜索.md b/problems/0700.二叉搜索树中的搜索.md index 13064f97..bc21bab8 100644 --- a/problems/0700.二叉搜索树中的搜索.md +++ b/problems/0700.二叉搜索树中的搜索.md @@ -18,9 +18,9 @@ 在上述示例中,如果要找的值是 5,但因为没有节点值为 5,我们应该返回 NULL。 -# 视频讲解 +## 算法公开课 -**《代码随想录》算法视频公开课:[不愧是搜索树,这次搜索有方向了!| LeetCode:700.二叉搜索树中的搜索](https://www.bilibili.com/video/BV1wG411g7sF),相信结合视频在看本篇题解,更有助于大家对本题的理解**。 +**[《代码随想录》算法视频公开课](https://programmercarl.com/other/gongkaike.html):[不愧是搜索树,这次搜索有方向了!| LeetCode:700.二叉搜索树中的搜索](https://www.bilibili.com/video/BV1wG411g7sF),相信结合视频在看本篇题解,更有助于大家对本题的理解**。 ## 思路 @@ -415,7 +415,7 @@ object Solution { } ``` -### rust +### Rust 递归: @@ -469,3 +469,4 @@ impl Solution { + From 7746734d79d4726143375aaf1a8a8f835483346e Mon Sep 17 00:00:00 2001 From: jinbudaily <18336218010@163.com> Date: Fri, 21 Jul 2023 20:22:33 +0800 Subject: [PATCH 090/122] =?UTF-8?q?=E6=9B=B4=E6=96=B0=200098.=E9=AA=8C?= =?UTF-8?q?=E8=AF=81=E4=BA=8C=E5=8F=89=E6=90=9C=E7=B4=A2=E6=A0=91=20?= =?UTF-8?q?=E6=8E=92=E7=89=88=E6=A0=BC=E5=BC=8F=E4=BF=AE=E5=A4=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- problems/0098.验证二叉搜索树.md | 29 +++++++++++++++-------------- 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/problems/0098.验证二叉搜索树.md b/problems/0098.验证二叉搜索树.md index 95b657a5..a48ec065 100644 --- a/problems/0098.验证二叉搜索树.md +++ b/problems/0098.验证二叉搜索树.md @@ -20,18 +20,18 @@ ![98.验证二叉搜索树](https://code-thinking-1253855093.file.myqcloud.com/pics/20230310000750.png) -# 视频讲解 +## 算法公开课 -**《代码随想录》算法视频公开课:[你对二叉搜索树了解的还不够! | LeetCode:98.验证二叉搜索树](https://www.bilibili.com/video/BV18P411n7Q4),相信结合视频在看本篇题解,更有助于大家对本题的理解**。 +**[《代码随想录》算法视频公开课](https://programmercarl.com/other/gongkaike.html):[你对二叉搜索树了解的还不够! | LeetCode:98.验证二叉搜索树](https://www.bilibili.com/video/BV18P411n7Q4),相信结合视频在看本篇题解,更有助于大家对本题的理解**。 -# 思路 +## 思路 要知道中序遍历下,输出的二叉搜索树节点的数值是有序序列。 有了这个特性,**验证二叉搜索树,就相当于变成了判断一个序列是不是递增的了。** -## 递归法 +### 递归法 可以递归中序遍历将二叉搜索树转变成一个数组,代码如下: @@ -211,7 +211,7 @@ public: 最后这份代码看上去整洁一些,思路也清晰。 -## 迭代法 +### 迭代法 可以用迭代法模拟二叉树中序遍历,对前中后序迭代法生疏的同学可以看这两篇[二叉树:听说递归能做的,栈也能做!](https://programmercarl.com/二叉树的迭代遍历.html),[二叉树:前中后序迭代方式统一写法](https://programmercarl.com/二叉树的统一迭代法.html) @@ -245,7 +245,7 @@ public: 在[二叉树:二叉搜索树登场!](https://programmercarl.com/0700.二叉搜索树中的搜索.html)中我们分明写出了痛哭流涕的简洁迭代法,怎么在这里不行了呢,因为本题是要验证二叉搜索树啊。 -# 总结 +## 总结 这道题目是一个简单题,但对于没接触过的同学还是有难度的。 @@ -254,10 +254,10 @@ public: 只要把基本类型的题目都做过,总结过之后,思路自然就开阔了。 -# 其他语言版本 +## 其他语言版本 -## Java +### Java ```Java //使用統一迭代法 @@ -369,7 +369,7 @@ class Solution { } ``` -## Python +### Python 递归法(版本一)利用中序递增性质,转换成数组 ```python @@ -479,7 +479,7 @@ class Solution: ``` -## Go +### Go ```Go func isValidBST(root *TreeNode) bool { @@ -526,7 +526,7 @@ func isValidBST(root *TreeNode) bool { } ``` -## JavaScript +### JavaScript 辅助数组解决 @@ -595,7 +595,7 @@ var isValidBST = function (root) { }; ``` -## TypeScript +### TypeScript > 辅助数组解决: @@ -637,7 +637,7 @@ function isValidBST(root: TreeNode | null): boolean { }; ``` -## Scala +### Scala 辅助数组解决: ```scala @@ -682,7 +682,7 @@ object Solution { } ``` -## rust +### Rust 递归: @@ -735,3 +735,4 @@ impl Solution { + From 74bbca292355dbc8ce9316329bfea503234ef0d6 Mon Sep 17 00:00:00 2001 From: jinbudaily <18336218010@163.com> Date: Fri, 21 Jul 2023 20:26:08 +0800 Subject: [PATCH 091/122] =?UTF-8?q?=E6=9B=B4=E6=96=B0=200530.=E4=BA=8C?= =?UTF-8?q?=E5=8F=89=E6=90=9C=E7=B4=A2=E6=A0=91=E7=9A=84=E6=9C=80=E5=B0=8F?= =?UTF-8?q?=E7=BB=9D=E5=AF=B9=E5=B7=AE=20=E6=8E=92=E7=89=88=E6=A0=BC?= =?UTF-8?q?=E5=BC=8F=E4=BF=AE=E5=A4=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- problems/0530.二叉搜索树的最小绝对差.md | 29 +++++++++++++------------ 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/problems/0530.二叉搜索树的最小绝对差.md b/problems/0530.二叉搜索树的最小绝对差.md index 3e4391d6..56911858 100644 --- a/problems/0530.二叉搜索树的最小绝对差.md +++ b/problems/0530.二叉搜索树的最小绝对差.md @@ -19,12 +19,12 @@ 提示:树中至少有 2 个节点。 -# 视频讲解 +## 算法公开课 -**《代码随想录》算法视频公开课:[二叉搜索树中,需要掌握如何双指针遍历!| LeetCode:530.二叉搜索树的最小绝对差](https://www.bilibili.com/video/BV1DD4y11779),相信结合视频在看本篇题解,更有助于大家对本题的理解**。 +**[《代码随想录》算法视频公开课](https://programmercarl.com/other/gongkaike.html):[二叉搜索树中,需要掌握如何双指针遍历!| LeetCode:530.二叉搜索树的最小绝对差](https://www.bilibili.com/video/BV1DD4y11779),相信结合视频在看本篇题解,更有助于大家对本题的理解**。 -# 思路 +## 思路 题目中要求在二叉搜索树上任意两节点的差的绝对值的最小值。 @@ -32,7 +32,7 @@ 遇到在二叉搜索树上求什么最值啊,差值之类的,就把它想成在一个有序数组上求最值,求差值,这样就简单多了。 -## 递归 +### 递归 那么二叉搜索树采用中序遍历,其实就是一个有序数组。 @@ -102,7 +102,7 @@ public: 是不是看上去也并不复杂! -## 迭代 +### 迭代 看过这两篇[二叉树:听说递归能做的,栈也能做!](https://programmercarl.com/二叉树的迭代遍历.html),[二叉树:前中后序迭代方式的写法就不能统一一下么?](https://programmercarl.com/二叉树的统一迭代法.html)文章之后,不难写出两种中序遍历的迭代法。 @@ -135,7 +135,7 @@ public: }; ``` -# 总结 +## 总结 **遇到在二叉搜索树上求什么最值,求差值之类的,都要思考一下二叉搜索树可是有序的,要利用好这一特点。** @@ -145,10 +145,10 @@ public: -# 其他语言版本 +## 其他语言版本 -## Java +### Java 递归 ```java @@ -235,7 +235,7 @@ class Solution { } } ``` -## Python +### Python 递归法(版本一)利用中序递增,结合数组 ```python @@ -313,7 +313,7 @@ class Solution: ``` -## Go: +### Go 中序遍历,然后计算最小差值 ```go @@ -340,7 +340,7 @@ func getMinimumDifference(root *TreeNode) int { } ``` -## JavaScript +### JavaScript 递归 先转换为有序数组 ```javascript /** @@ -415,7 +415,7 @@ var getMinimumDifference = function(root) { } ``` -## TypeScript +### TypeScript > 辅助数组解决 @@ -482,7 +482,7 @@ function getMinimumDifference(root: TreeNode | null): number { }; ``` -## Scala +### Scala 构建二叉树的有序数组: @@ -561,7 +561,7 @@ object Solution { } ``` -## rust +### Rust 构建二叉树的有序数组: @@ -652,3 +652,4 @@ impl Solution { + From c1da5bb2339fbe525eaf1cc4f09702b1caefbc1d Mon Sep 17 00:00:00 2001 From: El nino Date: Sun, 23 Jul 2023 10:12:24 +0800 Subject: [PATCH 092/122] =?UTF-8?q?typo=EF=BC=9B=E4=B8=BA=E4=BB=A3?= =?UTF-8?q?=E7=A0=81=E5=9D=97=E6=B7=BB=E5=8A=A0=20cpp=20=E8=AF=AD=E8=A8=80?= =?UTF-8?q?=E9=AB=98=E4=BA=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- problems/图论深搜理论基础.md | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/problems/图论深搜理论基础.md b/problems/图论深搜理论基础.md index eb6a26fe..af4073f0 100644 --- a/problems/图论深搜理论基础.md +++ b/problems/图论深搜理论基础.md @@ -16,13 +16,13 @@ ## dfs 与 bfs 区别 -提到深度优先搜索(dfs),就不得不说和广度优先有什么区别(bfs) +提到深度优先搜索(dfs),就不得不说和广度优先搜索(bfs)有什么区别 先来了解dfs的过程,很多录友可能对dfs(深度优先搜索),bfs(广度优先搜索)分不清。 先给大家说一下两者大概的区别: -* dfs是可一个方向去搜,不到黄河不回头,直到遇到绝境了,搜不下去了,在换方向(换方向的过程就涉及到了回溯)。 +* dfs是可一个方向去搜,不到黄河不回头,直到遇到绝境了,搜不下去了,再换方向(换方向的过程就涉及到了回溯)。 * bfs是先把本节点所连接的所有节点遍历一遍,走到下一个节点的时候,再把连接节点的所有节点遍历一遍,搜索方向更像是广度,四面八方的搜索过程。 当然以上讲的是,大体可以这么理解,接下来 我们详细讲解dfs,(bfs在用单独一篇文章详细讲解) @@ -60,26 +60,26 @@ 上图演示中,其实我并没有把 所有的 从节点1 到节点6的dfs(深度优先搜索)的过程都画出来,那样太冗余了,但 已经把dfs 关键的地方都涉及到了,关键就两点: -* 搜索方向,是认准一个方向搜,直到碰壁之后在换方向 +* 搜索方向,是认准一个方向搜,直到碰壁之后再换方向 * 换方向是撤销原路径,改为节点链接的下一个路径,回溯的过程。 ## 代码框架 -正式因为dfs搜索可一个方向,并需要回溯,所以用递归的方式来实现是最方便的。 +正是因为dfs搜索可一个方向,并需要回溯,所以用递归的方式来实现是最方便的。 -很多录友对回溯很陌生,建议先看看码随想录,[回溯算法章节](https://programmercarl.com/回溯算法理论基础.html)。 +很多录友对回溯很陌生,建议先看看代码随想录,[回溯算法章节](https://programmercarl.com/回溯算法理论基础.html)。 有递归的地方就有回溯,那么回溯在哪里呢? 就地递归函数的下面,例如如下代码: -``` +```cpp void dfs(参数) { 处理节点 dfs(图,选择的节点); // 递归 回溯,撤销处理结果 } -``` +``` 可以看到回溯操作就在递归函数的下面,递归和回溯是相辅相成的。 @@ -89,7 +89,7 @@ void dfs(参数) { 我们在回顾一下[回溯法](https://programmercarl.com/回溯算法理论基础.html)的代码框架: -``` +```cpp void backtracking(参数) { if (终止条件) { 存放结果; @@ -102,11 +102,11 @@ void backtracking(参数) { } } -``` +``` 回溯算法,其实就是dfs的过程,这里给出dfs的代码框架: -``` +```cpp void dfs(参数) { if (终止条件) { 存放结果; @@ -136,9 +136,9 @@ void dfs(参数) { 1. 确认递归函数,参数 -``` +```cpp void dfs(参数) -``` +``` 通常我们递归的时候,我们递归搜索需要了解哪些参数,其实也可以在写递归函数的时候,发现需要什么参数,再去补充就可以。 @@ -146,7 +146,7 @@ void dfs(参数) 例如这样: -``` +```cpp vector> result; // 保存符合条件的所有路径 vector path; // 起点到终点的路径 void dfs (图,目前搜索的节点) @@ -158,7 +158,7 @@ void dfs (图,目前搜索的节点) 终止条件很重要,很多同学写dfs的时候,之所以容易死循环,栈溢出等等这些问题,都是因为终止条件没有想清楚。 -``` +```cpp if (终止条件) { 存放结果; return; @@ -173,7 +173,7 @@ if (终止条件) { 一般这里就是一个for循环的操作,去遍历 目前搜索节点 所能到的所有节点。 -``` +```cpp for (选择:本节点所连接的其他节点) { 处理节点; dfs(图,选择的节点); // 递归 From b68e881a659e4ef56446db940fbf12a6a6a09207 Mon Sep 17 00:00:00 2001 From: El nino Date: Sun, 23 Jul 2023 11:08:46 +0800 Subject: [PATCH 093/122] typo --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index dd70d8cb..5fe165a7 100644 --- a/README.md +++ b/README.md @@ -396,7 +396,7 @@ * [图论:深度优先搜索理论基础](./problems/图论深搜理论基础.md) * [图论:797.所有可能的路径](./problems/0797.所有可能的路径.md) -* [图论:广度优先搜索理论基础](./problems/图论广索理论基础.md) +* [图论:广度优先搜索理论基础](./problems/图论广搜理论基础.md) * [图论:200.岛屿数量.深搜版](./problems/0200.岛屿数量.深搜版.md) * [图论:200.岛屿数量.广搜版](./problems/0200.岛屿数量.广搜版.md) * [图论:695.岛屿的最大面积](./problems/0695.岛屿的最大面积.md) From 55b85b5251c7b4f2060795070341eaf4d97347d0 Mon Sep 17 00:00:00 2001 From: jinbudaily <18336218010@163.com> Date: Sun, 23 Jul 2023 17:57:10 +0800 Subject: [PATCH 094/122] =?UTF-8?q?=E6=9B=B4=E6=96=B0=200501.=E4=BA=8C?= =?UTF-8?q?=E5=8F=89=E6=90=9C=E7=B4=A2=E6=A0=91=E4=B8=AD=E7=9A=84=E4=BC=97?= =?UTF-8?q?=E6=95=B0=20=E6=8E=92=E7=89=88=E6=A0=BC=E5=BC=8F=E4=BF=AE?= =?UTF-8?q?=E5=A4=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- problems/0501.二叉搜索树中的众数.md | 35 +++++++++++++++-------------- 1 file changed, 18 insertions(+), 17 deletions(-) diff --git a/problems/0501.二叉搜索树中的众数.md b/problems/0501.二叉搜索树中的众数.md index 1da32343..efbabc4a 100644 --- a/problems/0501.二叉搜索树中的众数.md +++ b/problems/0501.二叉搜索树中的众数.md @@ -33,20 +33,20 @@ 进阶:你可以不使用额外的空间吗?(假设由递归产生的隐式调用栈的开销不被计算在内) -# 算法公开课 +## 算法公开课 -**《代码随想录》算法视频公开课:[不仅双指针,还有代码技巧可以惊艳到你! | LeetCode:501.二叉搜索树中的众数](https://www.bilibili.com/video/BV1fD4y117gp),相信结合视频在看本篇题解,更有助于大家对本题的理解**。 +**[《代码随想录》算法视频公开课](https://programmercarl.com/other/gongkaike.html):[不仅双指针,还有代码技巧可以惊艳到你! | LeetCode:501.二叉搜索树中的众数](https://www.bilibili.com/video/BV1fD4y117gp),相信结合视频在看本篇题解,更有助于大家对本题的理解**。 -# 思路 +## 思路 这道题目呢,递归法我从两个维度来讲。 首先如果不是二叉搜索树的话,应该怎么解题,是二叉搜索树,又应该如何解题,两种方式做一个比较,可以加深大家对二叉树的理解。 -## 递归法 +### 递归法 -### 如果不是二叉搜索树 +#### 如果不是二叉搜索树 如果不是二叉搜索树,最直观的方法一定是把这个树都遍历了,用map统计频率,把频率排个序,最后取前面高频的元素的集合。 @@ -140,7 +140,7 @@ public: **所以如果本题没有说是二叉搜索树的话,那么就按照上面的思路写!** -### 是二叉搜索树 +#### 是二叉搜索树 **既然是搜索树,它中序遍历就是有序的**。 @@ -271,7 +271,7 @@ public: ``` -## 迭代法 +### 迭代法 只要把中序遍历转成迭代,中间节点的处理逻辑完全一样。 @@ -326,7 +326,7 @@ public: }; ``` -# 总结 +## 总结 本题在递归法中,我给出了如果是普通二叉树,应该怎么求众数。 @@ -345,10 +345,10 @@ public: > **需要强调的是 leetcode上的耗时统计是非常不准确的,看个大概就行,一样的代码耗时可以差百分之50以上**,所以leetcode的耗时统计别太当回事,知道理论上的效率优劣就行了。 -# 其他语言版本 +## 其他语言版本 -## Java +### Java 暴力法 @@ -472,7 +472,7 @@ class Solution { } } ``` -統一迭代法 +统一迭代法 ```Java class Solution { public int[] findMode(TreeNode root) { @@ -526,7 +526,7 @@ class Solution { ``` -## Python +### Python 递归法(版本一)利用字典 @@ -640,7 +640,7 @@ class Solution: return result ``` -## Go +### Go 计数法,不使用额外空间,利用二叉树性质,中序遍历 ```go @@ -676,7 +676,7 @@ func findMode(root *TreeNode) []int { } ``` -## JavaScript +### JavaScript 使用额外空间map的方法 ```javascript @@ -753,7 +753,7 @@ var findMode = function(root) { }; ``` -## TypeScript +### TypeScript > 辅助Map法 @@ -852,7 +852,7 @@ function findMode(root: TreeNode | null): number[] { }; ``` -## Scala +### Scala 暴力: ```scala @@ -923,7 +923,7 @@ object Solution { } ``` -## rust +### Rust 递归: @@ -1015,3 +1015,4 @@ pub fn find_mode(root: Option>>) -> Vec { + From 3a2490b92fe00b5e2b6acb602f33328b48e426ad Mon Sep 17 00:00:00 2001 From: jinbudaily <18336218010@163.com> Date: Sun, 23 Jul 2023 18:41:57 +0800 Subject: [PATCH 095/122] =?UTF-8?q?=E6=9B=B4=E6=96=B0=200236.=E4=BA=8C?= =?UTF-8?q?=E5=8F=89=E6=A0=91=E7=9A=84=E6=9C=80=E8=BF=91=E5=85=AC=E5=85=B1?= =?UTF-8?q?=E7=A5=96=E5=85=88=20=E6=8E=92=E7=89=88=E6=A0=BC=E5=BC=8F?= =?UTF-8?q?=E4=BF=AE=E5=A4=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- problems/0236.二叉树的最近公共祖先.md | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/problems/0236.二叉树的最近公共祖先.md b/problems/0236.二叉树的最近公共祖先.md index 0ebd5566..9db7409e 100644 --- a/problems/0236.二叉树的最近公共祖先.md +++ b/problems/0236.二叉树的最近公共祖先.md @@ -34,12 +34,12 @@ * 所有节点的值都是唯一的。 * p、q 为不同节点且均存在于给定的二叉树中。 -# 算法公开课 +## 算法公开课 -**《代码随想录》算法视频公开课:[自底向上查找,有点难度! | LeetCode:236. 二叉树的最近公共祖先](https://www.bilibili.com/video/BV1jd4y1B7E2),相信结合视频在看本篇题解,更有助于大家对本题的理解**。 +**[《代码随想录》算法视频公开课](https://programmercarl.com/other/gongkaike.html):[自底向上查找,有点难度! | LeetCode:236. 二叉树的最近公共祖先](https://www.bilibili.com/video/BV1jd4y1B7E2),相信结合视频在看本篇题解,更有助于大家对本题的理解**。 -# 思路 +## 思路 遇到这个题目首先想的是要是能自底向上查找就好了,这样就可以找到公共祖先了。 @@ -226,7 +226,7 @@ public: }; ``` -# 总结 +## 总结 这道题目刷过的同学未必真正了解这里面回溯的过程,以及结果是如何一层一层传上去的。 @@ -243,10 +243,10 @@ public: 本题没有给出迭代法,因为迭代法不适合模拟回溯的过程。理解递归的解法就够了。 -# 其他语言版本 +## 其他语言版本 -## Java +### Java ```Java class Solution { @@ -273,7 +273,7 @@ class Solution { ``` -## Python +### Python 递归法(版本一) ```python class Solution: @@ -312,7 +312,7 @@ class Solution: return left ``` -## Go +### Go ```Go func lowestCommonAncestor(root, p, q *TreeNode) *TreeNode { @@ -343,7 +343,7 @@ func lowestCommonAncestor(root, p, q *TreeNode) *TreeNode { } ``` -## JavaScript +### JavaScript ```javascript var lowestCommonAncestor = function(root, p, q) { @@ -370,7 +370,7 @@ var lowestCommonAncestor = function(root, p, q) { }; ``` -## TypeScript +### TypeScript ```typescript function lowestCommonAncestor(root: TreeNode | null, p: TreeNode | null, q: TreeNode | null): TreeNode | null { @@ -384,7 +384,7 @@ function lowestCommonAncestor(root: TreeNode | null, p: TreeNode | null, q: Tree }; ``` -## Scala +### Scala ```scala object Solution { @@ -404,7 +404,7 @@ object Solution { } ``` -## rust +### Rust ```rust impl Solution { @@ -436,3 +436,4 @@ impl Solution { + From 07e1ccca1925d16b5f9f58050d135d3a326b44af Mon Sep 17 00:00:00 2001 From: jinbudaily <18336218010@163.com> Date: Sun, 23 Jul 2023 18:52:09 +0800 Subject: [PATCH 096/122] =?UTF-8?q?=E6=9B=B4=E6=96=B0=200235.=E4=BA=8C?= =?UTF-8?q?=E5=8F=89=E6=90=9C=E7=B4=A2=E6=A0=91=E7=9A=84=E6=9C=80=E8=BF=91?= =?UTF-8?q?=E5=85=AC=E5=85=B1=E7=A5=96=E5=85=88=20=E6=8E=92=E7=89=88?= =?UTF-8?q?=E6=A0=BC=E5=BC=8F=E4=BF=AE=E5=A4=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- problems/0235.二叉搜索树的最近公共祖先.md | 29 ++++++++++++----------- 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/problems/0235.二叉搜索树的最近公共祖先.md b/problems/0235.二叉搜索树的最近公共祖先.md index 9777bb0b..2b8af060 100644 --- a/problems/0235.二叉搜索树的最近公共祖先.md +++ b/problems/0235.二叉搜索树的最近公共祖先.md @@ -36,11 +36,11 @@ * 所有节点的值都是唯一的。 * p、q 为不同节点且均存在于给定的二叉搜索树中。 -# 算法公开课 +## 算法公开课 -**《代码随想录》算法视频公开课:[二叉搜索树找祖先就有点不一样了!| 235. 二叉搜索树的最近公共祖先](https://www.bilibili.com/video/BV1Zt4y1F7ww?share_source=copy_web),相信结合视频在看本篇题解,更有助于大家对本题的理解**。 +**[《代码随想录》算法视频公开课](https://programmercarl.com/other/gongkaike.html):[二叉搜索树找祖先就有点不一样了!| 235. 二叉搜索树的最近公共祖先](https://www.bilibili.com/video/BV1Zt4y1F7ww?share_source=copy_web),相信结合视频在看本篇题解,更有助于大家对本题的理解**。 -# 思路 +## 思路 做过[二叉树:公共祖先问题](https://programmercarl.com/0236.二叉树的最近公共祖先.html)题目的同学应该知道,利用回溯从底向上搜索,遇到一个节点的左子树里有p,右子树里有q,那么当前节点就是最近公共祖先。 @@ -71,7 +71,7 @@ 可以看出直接按照指定的方向,就可以找到节点8,为最近公共祖先,而且不需要遍历整棵树,找到结果直接返回! -## 递归法 +### 递归法 递归三部曲如下: @@ -203,7 +203,7 @@ public: }; ``` -## 迭代法 +### 迭代法 对于二叉搜索树的迭代法,大家应该在[二叉树:二叉搜索树登场!](https://programmercarl.com/0700.二叉搜索树中的搜索.html)就了解了。 @@ -229,7 +229,7 @@ public: 灵魂拷问:是不是又被简单的迭代法感动到痛哭流涕? -# 总结 +## 总结 对于二叉搜索树的最近祖先问题,其实要比[普通二叉树公共祖先问题](https://programmercarl.com/0236.二叉树的最近公共祖先.html)简单的多。 @@ -238,10 +238,10 @@ public: 最后给出了对应的迭代法,二叉搜索树的迭代法甚至比递归更容易理解,也是因为其有序性(自带方向性),按照目标区间找就行了。 -# 其他语言版本 +## 其他语言版本 -## Java +### Java 递归法: ```java @@ -273,7 +273,7 @@ class Solution { ``` -## Python +### Python 递归法(版本一) ```python @@ -326,7 +326,7 @@ class Solution: ``` -## Go +### Go 递归法: ```go @@ -350,7 +350,7 @@ func lowestCommonAncestor(root, p, q *TreeNode) *TreeNode { ``` -## JavaScript +### JavaScript 递归法: ```javascript @@ -391,7 +391,7 @@ var lowestCommonAncestor = function(root, p, q) { }; ``` -## TypeScript +### TypeScript > 递归法: @@ -422,7 +422,7 @@ function lowestCommonAncestor(root: TreeNode | null, p: TreeNode | null, q: Tree }; ``` -## Scala +### Scala 递归: @@ -453,7 +453,7 @@ object Solution { } ``` -## rust +### Rust 递归: @@ -519,3 +519,4 @@ impl Solution { + From 70271161fff40fb3ab1929dcb37b19e3efe469b0 Mon Sep 17 00:00:00 2001 From: jinbudaily <18336218010@163.com> Date: Sun, 23 Jul 2023 18:54:12 +0800 Subject: [PATCH 097/122] =?UTF-8?q?=E6=9B=B4=E6=96=B0=200701.=E4=BA=8C?= =?UTF-8?q?=E5=8F=89=E6=90=9C=E7=B4=A2=E6=A0=91=E4=B8=AD=E7=9A=84=E6=8F=92?= =?UTF-8?q?=E5=85=A5=E6=93=8D=E4=BD=9C=20=E6=8E=92=E7=89=88=E6=A0=BC?= =?UTF-8?q?=E5=BC=8F=E4=BF=AE=E5=A4=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- problems/0701.二叉搜索树中的插入操作.md | 29 +++++++++++++------------ 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/problems/0701.二叉搜索树中的插入操作.md b/problems/0701.二叉搜索树中的插入操作.md index fc4351ba..511d161c 100644 --- a/problems/0701.二叉搜索树中的插入操作.md +++ b/problems/0701.二叉搜索树中的插入操作.md @@ -23,11 +23,11 @@ * -10^8 <= val <= 10^8 * 新值和原始二叉搜索树中的任意节点值都不同 -# 算法公开课 +## 算法公开课 -**《代码随想录》算法视频公开课:[原来这么简单? | LeetCode:701.二叉搜索树中的插入操作](https://www.bilibili.com/video/BV1Et4y1c78Y?share_source=copy_web),相信结合视频在看本篇题解,更有助于大家对本题的理解**。 +**[《代码随想录》算法视频公开课](https://programmercarl.com/other/gongkaike.html):[原来这么简单? | LeetCode:701.二叉搜索树中的插入操作](https://www.bilibili.com/video/BV1Et4y1c78Y?share_source=copy_web),相信结合视频在看本篇题解,更有助于大家对本题的理解**。 -# 思路 +## 思路 这道题目其实是一道简单题目,**但是题目中的提示:有多种有效的插入方式,还可以重构二叉搜索树,一下子吓退了不少人**,瞬间感觉题目复杂了很多。 @@ -43,7 +43,7 @@ 接下来就是遍历二叉搜索树的过程了。 -## 递归 +### 递归 递归三部曲: @@ -165,7 +165,7 @@ public: **网上千篇一律的代码,可能会误导大家认为通过递归函数返回节点 这样的写法是天经地义,其实这里是有优化的!** -## 迭代 +### 迭代 再来看看迭代法,对二叉搜索树迭代写法不熟悉,可以看这篇:[二叉树:二叉搜索树登场!](https://programmercarl.com/0700.二叉搜索树中的搜索.html) @@ -198,7 +198,7 @@ public: }; ``` -# 总结 +## 总结 首先在二叉搜索树中的插入操作,大家不用恐惧其重构搜索树,其实根本不用重构。 @@ -207,9 +207,9 @@ public: 最后依然给出了迭代的方法,迭代的方法就需要记录当前遍历节点的父节点了,这个和没有返回值的递归函数实现的代码逻辑是一样的。 -# 其他语言版本 +## 其他语言版本 -## Java +### Java ```java class Solution { @@ -254,7 +254,7 @@ class Solution { } ``` ----- -## Python +### Python 递归法(版本一) ```python @@ -371,7 +371,7 @@ class Solution: ``` ----- -## Go +### Go 递归法 @@ -417,7 +417,7 @@ func insertIntoBST(root *TreeNode, val int) *TreeNode { } ``` ----- -## JavaScript +### JavaScript 有返回值的递归写法 @@ -530,7 +530,7 @@ var insertIntoBST = function (root, val) { }; ``` -## TypeScript +### TypeScript > 递归-有返回值 @@ -595,7 +595,7 @@ function insertIntoBST(root: TreeNode | null, val: number): TreeNode | null { ``` -## Scala +### Scala 递归: @@ -632,7 +632,7 @@ object Solution { } ``` -### rust +### Rust 迭代: @@ -697,3 +697,4 @@ impl Solution { + From 0f22ada3df0468334a45059a037ec6a7fa198d85 Mon Sep 17 00:00:00 2001 From: jinbudaily <18336218010@163.com> Date: Sun, 23 Jul 2023 18:56:18 +0800 Subject: [PATCH 098/122] =?UTF-8?q?=E6=9B=B4=E6=96=B0=200450.=E5=88=A0?= =?UTF-8?q?=E9=99=A4=E4=BA=8C=E5=8F=89=E6=90=9C=E7=B4=A2=E6=A0=91=E4=B8=AD?= =?UTF-8?q?=E7=9A=84=E8=8A=82=E7=82=B9=20=E6=8E=92=E7=89=88=E6=A0=BC?= =?UTF-8?q?=E5=BC=8F=E4=BF=AE=E5=A4=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- problems/0450.删除二叉搜索树中的节点.md | 31 +++++++++++++------------ 1 file changed, 16 insertions(+), 15 deletions(-) diff --git a/problems/0450.删除二叉搜索树中的节点.md b/problems/0450.删除二叉搜索树中的节点.md index 3d73598d..13599fd8 100644 --- a/problems/0450.删除二叉搜索树中的节点.md +++ b/problems/0450.删除二叉搜索树中的节点.md @@ -24,15 +24,15 @@ ![450.删除二叉搜索树中的节点](https://code-thinking-1253855093.file.myqcloud.com/pics/20201020171048265.png) -# 算法公开课 +## 算法公开课 -**《代码随想录》算法视频公开课:[调整二叉树的结构最难!| LeetCode:450.删除二叉搜索树中的节点](https://www.bilibili.com/video/BV1tP41177us?share_source=copy_web),相信结合视频在看本篇题解,更有助于大家对本题的理解**。 +**[《代码随想录》算法视频公开课](https://programmercarl.com/other/gongkaike.html):[调整二叉树的结构最难!| LeetCode:450.删除二叉搜索树中的节点](https://www.bilibili.com/video/BV1tP41177us?share_source=copy_web),相信结合视频在看本篇题解,更有助于大家对本题的理解**。 -# 思路 +## 思路 搜索树的节点删除要比节点增加复杂的多,有很多情况需要考虑,做好心理准备。 -## 递归 +### 递归 递归三部曲: @@ -161,7 +161,7 @@ public: }; ``` -## 普通二叉树的删除方式 +### 普通二叉树的删除方式 这里我在介绍一种通用的删除,普通二叉树的删除方式(没有使用搜索树的特性,遍历整棵树),用交换值的操作来删除目标节点。 @@ -198,7 +198,7 @@ public: 这个代码是简短一些,思路也巧妙,但是不太好想,实操性不强,推荐第一种写法! -## 迭代法 +### 迭代法 删除节点的迭代法还是复杂一些的,但其本质我在递归法里都介绍了,最关键就是删除节点的操作(动画模拟的过程) @@ -246,7 +246,7 @@ public: }; ``` -# 总结 +## 总结 读完本篇,大家会发现二叉搜索树删除节点比增加节点复杂的多。 @@ -264,10 +264,10 @@ public: 迭代法其实不太容易写出来,所以如果是初学者的话,彻底掌握第一种递归写法就够了。 -# 其他语言版本 +## 其他语言版本 -## Java +### Java ```java class Solution { public TreeNode deleteNode(TreeNode root, int key) { @@ -323,7 +323,7 @@ class Solution { } ``` -## Python +### Python 递归法(版本一) ```python class Solution: @@ -411,7 +411,7 @@ class Solution: return root ``` -## Go +### Go ```Go // 递归版本 func deleteNode(root *TreeNode, key int) *TreeNode { @@ -497,7 +497,7 @@ func deleteNode(root *TreeNode, key int) *TreeNode { } ``` -## JavaScript +### JavaScript 递归 @@ -588,7 +588,7 @@ var deleteNode = function (root, key) { } ``` -## TypeScript +### TypeScript > 递归法: @@ -652,7 +652,7 @@ function deleteNode(root: TreeNode | null, key: number): TreeNode | null { }; ``` -## Scala +### Scala ```scala object Solution { @@ -682,7 +682,7 @@ object Solution { } ``` -## rust +### Rust ```rust impl Solution { @@ -720,3 +720,4 @@ impl Solution { + From e14e2169c4c303d5e690705245230323774df795 Mon Sep 17 00:00:00 2001 From: jinbudaily <18336218010@163.com> Date: Sun, 23 Jul 2023 18:58:10 +0800 Subject: [PATCH 099/122] =?UTF-8?q?=E6=9B=B4=E6=96=B0=200669.=E4=BF=AE?= =?UTF-8?q?=E5=89=AA=E4=BA=8C=E5=8F=89=E6=90=9C=E7=B4=A2=E6=A0=91=20?= =?UTF-8?q?=E6=8E=92=E7=89=88=E6=A0=BC=E5=BC=8F=E4=BF=AE=E5=A4=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- problems/0669.修剪二叉搜索树.md | 29 +++++++++++++++-------------- 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/problems/0669.修剪二叉搜索树.md b/problems/0669.修剪二叉搜索树.md index 85922a1d..2cfbfefc 100644 --- a/problems/0669.修剪二叉搜索树.md +++ b/problems/0669.修剪二叉搜索树.md @@ -20,17 +20,17 @@ ![669.修剪二叉搜索树1](https://code-thinking-1253855093.file.myqcloud.com/pics/20201014173219142.png) -# 算法公开课 +## 算法公开课 -**《代码随想录》算法视频公开课:[你修剪的方式不对,我来给你纠正一下!| LeetCode:669. 修剪二叉搜索树](https://www.bilibili.com/video/BV17P41177ud?share_source=copy_web),相信结合视频在看本篇题解,更有助于大家对本题的理解**。 +**[《代码随想录》算法视频公开课](https://programmercarl.com/other/gongkaike.html):[你修剪的方式不对,我来给你纠正一下!| LeetCode:669. 修剪二叉搜索树](https://www.bilibili.com/video/BV17P41177ud?share_source=copy_web),相信结合视频在看本篇题解,更有助于大家对本题的理解**。 -# 思路 +## 思路 相信看到这道题目大家都感觉是一道简单题(事实上leetcode上也标明是简单)。 但还真的不简单! -## 递归法 +### 递归法 直接想法就是:递归处理,然后遇到 `root->val < low || root->val > high` 的时候直接return NULL,一波修改,赶紧利落。 @@ -188,7 +188,7 @@ public: 只看代码,其实不太好理解节点是如何移除的,这一块大家可以自己再模拟模拟! -## 迭代法 +### 迭代法 因为二叉搜索树的有序性,不需要使用栈模拟递归的过程。 @@ -233,7 +233,7 @@ public: }; ``` -# 总结 +## 总结 修剪二叉搜索树其实并不难,但在递归法中大家可看出我费了很大的功夫来讲解如何删除节点的,这个思路其实是比较绕的。 @@ -243,10 +243,10 @@ public: 本题我依然给出递归法和迭代法,初学者掌握递归就可以了,如果想进一步学习,就把迭代法也写一写。 -# 其他语言版本 +## 其他语言版本 -## Java +### Java **递归** @@ -311,7 +311,7 @@ class Solution { ```` -## Python +### Python 递归法(版本一) ```python @@ -381,7 +381,7 @@ class Solution: ``` -## Go +### Go ```go // 递归 @@ -436,7 +436,7 @@ func trimBST(root *TreeNode, low int, high int) *TreeNode { ``` -## JavaScript版本 +### JavaScript 迭代: @@ -492,7 +492,7 @@ var trimBST = function (root,low,high) { } ``` -## TypeScript +### TypeScript > 递归法 @@ -540,7 +540,7 @@ function trimBST(root: TreeNode | null, low: number, high: number): TreeNode | n }; ``` -## Scala +### Scala 递归法: @@ -557,7 +557,7 @@ object Solution { } ``` -## rust +### Rust // 递归 @@ -590,3 +590,4 @@ impl Solution { + From 572c08984f9ec9821383b3c9a51dbbf1684eb6af Mon Sep 17 00:00:00 2001 From: jinbudaily <18336218010@163.com> Date: Sun, 23 Jul 2023 19:00:08 +0800 Subject: [PATCH 100/122] =?UTF-8?q?=E6=9B=B4=E6=96=B0=200108.=E5=B0=86?= =?UTF-8?q?=E6=9C=89=E5=BA=8F=E6=95=B0=E7=BB=84=E8=BD=AC=E6=8D=A2=E4=B8=BA?= =?UTF-8?q?=E4=BA=8C=E5=8F=89=E6=90=9C=E7=B4=A2=E6=A0=91=20=E6=8E=92?= =?UTF-8?q?=E7=89=88=E6=A0=BC=E5=BC=8F=E4=BF=AE=E5=A4=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- problems/0108.将有序数组转换为二叉搜索树.md | 31 +++++++++++---------- 1 file changed, 16 insertions(+), 15 deletions(-) diff --git a/problems/0108.将有序数组转换为二叉搜索树.md b/problems/0108.将有序数组转换为二叉搜索树.md index 056ef3e2..e699005e 100644 --- a/problems/0108.将有序数组转换为二叉搜索树.md +++ b/problems/0108.将有序数组转换为二叉搜索树.md @@ -20,11 +20,11 @@ ![108.将有序数组转换为二叉搜索树](https://code-thinking-1253855093.file.myqcloud.com/pics/20201022164420763.png) -# 算法公开课 +## 算法公开课 -**《代码随想录》算法视频公开课:[构造平衡二叉搜索树!| LeetCode:108.将有序数组转换为二叉搜索树](https://www.bilibili.com/video/BV1uR4y1X7qL?share_source=copy_web),相信结合视频在看本篇题解,更有助于大家对本题的理解**。 +**[《代码随想录》算法视频公开课](https://programmercarl.com/other/gongkaike.html):[构造平衡二叉搜索树!| LeetCode:108.将有序数组转换为二叉搜索树](https://www.bilibili.com/video/BV1uR4y1X7qL?share_source=copy_web),相信结合视频在看本篇题解,更有助于大家对本题的理解**。 -# 思路 +## 思路 做这道题目之前大家可以了解一下这几道: @@ -71,7 +71,7 @@ **这也是题目中强调答案不是唯一的原因。 理解这一点,这道题目算是理解到位了**。 -## 递归 +### 递归 递归三部曲: @@ -155,7 +155,7 @@ public: **注意:在调用traversal的时候传入的left和right为什么是0和nums.size() - 1,因为定义的区间为左闭右闭**。 -## 迭代法 +### 迭代法 迭代法可以通过三个队列来模拟,一个队列放遍历的节点,一个队列放左区间下标,一个队列放右区间下标。 @@ -203,7 +203,7 @@ public: }; ``` -# 总结 +## 总结 **在[二叉树:构造二叉树登场!](https://programmercarl.com/0106.从中序与后序遍历序列构造二叉树.html) 和 [二叉树:构造一棵最大的二叉树](https://programmercarl.com/0654.最大二叉树.html)之后,我们顺理成章的应该构造一下二叉搜索树了,一不小心还是一棵平衡二叉搜索树**。 @@ -216,10 +216,10 @@ public: 最后依然给出迭代的方法,其实就是模拟取中间元素,然后不断分割去构造二叉树的过程。 -# 其他语言版本 +## 其他语言版本 -## Java +### Java 递归: 左闭右开 [left,right) ```Java @@ -315,7 +315,7 @@ class Solution { } ``` -## Python +### Python 递归法 ```python class Solution: @@ -377,7 +377,7 @@ class Solution: ``` -## Go +### Go 递归(隐含回溯) @@ -396,7 +396,7 @@ func sortedArrayToBST(nums []int) *TreeNode { } ``` -## JavaScript +### JavaScript 递归 ```javascript @@ -453,7 +453,7 @@ var sortedArrayToBST = function(nums) { return root; }; ``` -## TypeScript +### TypeScript ```typescript function sortedArrayToBST(nums: number[]): TreeNode | null { @@ -469,7 +469,7 @@ function sortedArrayToBST(nums: number[]): TreeNode | null { }; ``` -## C +### C 递归 ```c @@ -490,7 +490,7 @@ struct TreeNode* sortedArrayToBST(int* nums, int numsSize) { } ``` -## Scala +### Scala 递归: @@ -511,7 +511,7 @@ object Solution { } ``` -## rust +### Rust 递归: @@ -536,3 +536,4 @@ impl Solution { + From 6bf34cd8ba3837d16013dd2ac78b5d632f3f2e22 Mon Sep 17 00:00:00 2001 From: jinbudaily <18336218010@163.com> Date: Sun, 23 Jul 2023 19:02:05 +0800 Subject: [PATCH 101/122] =?UTF-8?q?=E6=9B=B4=E6=96=B0=200538.=E5=B0=86?= =?UTF-8?q?=E4=BA=8C=E5=8F=89=E6=90=9C=E7=B4=A2=E6=A0=91=E8=BD=AC=E6=8D=A2?= =?UTF-8?q?=E4=B8=BA=E7=B4=AF=E5=8A=A0=E6=A0=91=20=E6=8E=92=E7=89=88?= =?UTF-8?q?=E6=A0=BC=E5=BC=8F=E4=BF=AE=E5=A4=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- problems/0538.把二叉搜索树转换为累加树.md | 35 ++++++++++++----------- 1 file changed, 18 insertions(+), 17 deletions(-) diff --git a/problems/0538.把二叉搜索树转换为累加树.md b/problems/0538.把二叉搜索树转换为累加树.md index 781763a4..c403c98f 100644 --- a/problems/0538.把二叉搜索树转换为累加树.md +++ b/problems/0538.把二叉搜索树转换为累加树.md @@ -44,11 +44,11 @@ * 树中的所有值 互不相同 。 * 给定的树为二叉搜索树。 -# 算法公开课 +## 算法公开课 -**《代码随想录》算法视频公开课:[普大喜奔!二叉树章节已全部更完啦!| LeetCode:538.把二叉搜索树转换为累加树](https://www.bilibili.com/video/BV1d44y1f7wP?share_source=copy_web),相信结合视频在看本篇题解,更有助于大家对本题的理解**。 +**[《代码随想录》算法视频公开课](https://programmercarl.com/other/gongkaike.html):[普大喜奔!二叉树章节已全部更完啦!| LeetCode:538.把二叉搜索树转换为累加树](https://www.bilibili.com/video/BV1d44y1f7wP?share_source=copy_web),相信结合视频在看本篇题解,更有助于大家对本题的理解**。 -# 思路 +## 思路 一看到累加树,相信很多小伙伴都会疑惑:如何累加?遇到一个节点,然后再遍历其他节点累加?怎么一想这么麻烦呢。 @@ -64,7 +64,7 @@ 那么知道如何遍历这个二叉树,也就迎刃而解了,**从树中可以看出累加的顺序是右中左,所以我们需要反中序遍历这个二叉树,然后顺序累加就可以了**。 -## 递归 +### 递归 遍历顺序如图所示: @@ -131,7 +131,7 @@ public: }; ``` -## 迭代法 +### 迭代法 迭代法其实就是中序模板题了,在[二叉树:前中后序迭代法](https://programmercarl.com/二叉树的迭代遍历.html)和[二叉树:前中后序统一方式迭代法](https://programmercarl.com/二叉树的统一迭代法.html)可以选一种自己习惯的写法。 @@ -166,17 +166,17 @@ public: }; ``` -# 总结 +## 总结 经历了前面各种二叉树增删改查的洗礼之后,这道题目应该比较简单了。 **好了,二叉树已经接近尾声了,接下来就是要对二叉树来一个大总结了**。 -# 其他语言版本 +## 其他语言版本 -## Java +### Java **递归** ```Java @@ -237,7 +237,7 @@ class Solution { } ``` -## Python +### Python 递归法(版本一) ```python # Definition for a binary tree node. @@ -318,7 +318,7 @@ class Solution: self.traversal(root) return root -``` +``` 迭代法(版本二) ```python class Solution: @@ -338,9 +338,9 @@ class Solution: pre = cur.val cur =cur.left return root -``` +``` -## Go +### Go 弄一个sum暂存其和值 ```go @@ -362,7 +362,7 @@ func traversal(cur *TreeNode) { } ``` -## JavaScript +### JavaScript 递归 ```javascript @@ -401,7 +401,7 @@ var convertBST = function (root) { }; ``` -##C +### C 递归 ```c @@ -422,7 +422,7 @@ struct TreeNode* convertBST(struct TreeNode* root){ } ``` -## TypeScript +### TypeScript > 递归法 @@ -462,7 +462,7 @@ function convertBST(root: TreeNode | null): TreeNode | null { }; ``` -## Scala +### Scala ```scala object Solution { @@ -481,7 +481,7 @@ object Solution { } ``` -## rust +### Rust 递归: @@ -535,3 +535,4 @@ impl Solution { + From 75390603854b899d5a164b0cf508ec393aaa3712 Mon Sep 17 00:00:00 2001 From: jinbudaily <18336218010@163.com> Date: Sun, 23 Jul 2023 19:04:13 +0800 Subject: [PATCH 102/122] =?UTF-8?q?=E6=9B=B4=E6=96=B0=20=E4=BA=8C=E5=8F=89?= =?UTF-8?q?=E6=A0=91=E6=80=BB=E7=BB=93=E7=AF=87=20=E6=8E=92=E7=89=88?= =?UTF-8?q?=E6=A0=BC=E5=BC=8F=E4=BF=AE=E5=A4=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- problems/二叉树总结篇.md | 20 ++------------------ 1 file changed, 2 insertions(+), 18 deletions(-) diff --git a/problems/二叉树总结篇.md b/problems/二叉树总结篇.md index 4c742a6b..82949543 100644 --- a/problems/二叉树总结篇.md +++ b/problems/二叉树总结篇.md @@ -92,7 +92,7 @@ * 递归:中序,双指针操作 * 迭代:模拟中序,逻辑相同 * [求二叉搜索树的众数](https://programmercarl.com/0501.二叉搜索树中的众数.html) - + * 递归:中序,清空结果集的技巧,遍历一遍便可求众数集合 * [二叉搜索树转成累加树](https://programmercarl.com/0538.把二叉搜索树转换为累加树.html) @@ -154,29 +154,13 @@ 这个图是 [代码随想录知识星球](https://programmercarl.com/other/kstar.html) 成员:[青](https://wx.zsxq.com/dweb2/index/footprint/185251215558842),所画,总结的非常好,分享给大家。 - **最后,二叉树系列就这么完美结束了,估计这应该是最长的系列了,感谢大家33天的坚持与陪伴,接下来我们又要开始新的系列了「回溯算法」!** - - -## 其他语言版本 - - -Java: - - -Python: - - -Go: - - - -

+ From 6e613877f24394d2e4da3f97580d5e75be7d3b83 Mon Sep 17 00:00:00 2001 From: jinbudaily <18336218010@163.com> Date: Mon, 24 Jul 2023 10:54:21 +0800 Subject: [PATCH 103/122] =?UTF-8?q?=E6=9B=B4=E6=96=B0=20=E5=9B=9E=E6=BA=AF?= =?UTF-8?q?=E7=AE=97=E6=B3=95=E7=90=86=E8=AE=BA=E5=9F=BA=E7=A1=80=20?= =?UTF-8?q?=E6=8E=92=E7=89=88=E6=A0=BC=E5=BC=8F=E4=BF=AE=E5=A4=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- problems/回溯算法理论基础.md | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/problems/回溯算法理论基础.md b/problems/回溯算法理论基础.md index f11dbaef..dff1823c 100644 --- a/problems/回溯算法理论基础.md +++ b/problems/回溯算法理论基础.md @@ -6,13 +6,19 @@ # 回溯算法理论基础 -## 题目分类大纲如下: +## 题目分类 回溯算法大纲 -可以配合我的B站视频:[带你学透回溯算法(理论篇)](https://www.bilibili.com/video/BV1cy4y167mM/) 一起学习! +## 算法公开课 -## 什么是回溯法 + + +**[《代码随想录》算法视频公开课](https://programmercarl.com/other/gongkaike.html):[带你学透回溯算法(理论篇)](https://www.bilibili.com/video/BV1cy4y167mM/),相信结合视频再看本篇题解,更有助于大家对本题的理解。** + +## 理论基础 + +### 什么是回溯法 回溯法也可以叫做回溯搜索法,它是一种搜索的方式。 @@ -22,7 +28,7 @@ **所以以下讲解中,回溯函数也就是递归函数,指的都是一个函数**。 -## 回溯法的效率 +### 回溯法的效率 回溯法的性能如何呢,这里要和大家说清楚了,**虽然回溯法很难,很不好理解,但是回溯法并不是什么高效的算法**。 @@ -34,7 +40,7 @@ 此时大家应该好奇了,都什么问题,这么牛逼,只能暴力搜索。 -## 回溯法解决的问题 +### 回溯法解决的问题 回溯法,一般可以解决如下几种问题: @@ -55,7 +61,7 @@ 记住组合无序,排列有序,就可以了。 -## 如何理解回溯法 +### 如何理解回溯法 **回溯法解决的问题都可以抽象为树形结构**,是的,我指的是所有回溯法的问题都可以抽象为树形结构! @@ -66,7 +72,7 @@ 这块可能初学者还不太理解,后面的回溯算法解决的所有题目中,我都会强调这一点并画图举相应的例子,现在有一个印象就行。 -## 回溯法模板 +### 回溯法模板 这里给出Carl总结的回溯算法模板。 @@ -173,3 +179,4 @@ void backtracking(参数) { + From 6f3fdf7286c92830e0e9feff8fbdca90442af159 Mon Sep 17 00:00:00 2001 From: jinbudaily <18336218010@163.com> Date: Mon, 24 Jul 2023 10:59:00 +0800 Subject: [PATCH 104/122] =?UTF-8?q?=E6=9B=B4=E6=96=B0=200077.=E7=BB=84?= =?UTF-8?q?=E5=90=88=20=E6=8E=92=E7=89=88=E6=A0=BC=E5=BC=8F=E4=BF=AE?= =?UTF-8?q?=E5=A4=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- problems/0077.组合.md | 19 ++++++------------- 1 file changed, 6 insertions(+), 13 deletions(-) diff --git a/problems/0077.组合.md b/problems/0077.组合.md index 444e15ce..702ffafe 100644 --- a/problems/0077.组合.md +++ b/problems/0077.组合.md @@ -5,10 +5,6 @@

参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!

- - - - # 第77题. 组合 [力扣题目链接](https://leetcode.cn/problems/combinations/ ) @@ -27,13 +23,12 @@ [1,4], ] -# 算法公开课 +## 算法公开课 + +**[《代码随想录》算法视频公开课](https://programmercarl.com/other/gongkaike.html):[带你学透回溯算法-组合问题(对应力扣题目:77.组合)](https://www.bilibili.com/video/BV1ti4y1L7cv),[组合问题的剪枝操作](https://www.bilibili.com/video/BV1wi4y157er),相信结合视频在看本篇题解,更有助于大家对本题的理解**。 -**《代码随想录》算法视频公开课:[带你学透回溯算法-组合问题(对应力扣题目:77.组合)](https://www.bilibili.com/video/BV1ti4y1L7cv),[组合问题的剪枝操作](https://www.bilibili.com/video/BV1wi4y157er),相信结合视频在看本篇题解,更有助于大家对本题的理解**。 - - -# 思路 +## 思路 本题是回溯法的经典题目。 @@ -345,12 +340,10 @@ public: - - ## 其他语言版本 -### Java: +### Java ```java class Solution { @@ -451,7 +444,7 @@ func dfs(n int, k int, start int) { } ``` -### javascript +### Javascript 剪枝: From f5e50a919d84cc41b00843a403ad3b566ac521b2 Mon Sep 17 00:00:00 2001 From: jinbudaily <18336218010@163.com> Date: Mon, 24 Jul 2023 11:02:27 +0800 Subject: [PATCH 105/122] =?UTF-8?q?=E6=9B=B4=E6=96=B0=20=E7=BB=84=E5=90=88?= =?UTF-8?q?=E4=BC=98=E5=8C=96=20=E6=8E=92=E7=89=88=E6=A0=BC=E5=BC=8F?= =?UTF-8?q?=E4=BF=AE=E5=A4=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- problems/0077.组合优化.md | 34 ++++++++++++++++++---------------- 1 file changed, 18 insertions(+), 16 deletions(-) diff --git a/problems/0077.组合优化.md b/problems/0077.组合优化.md index 3926d006..9577d65f 100644 --- a/problems/0077.组合优化.md +++ b/problems/0077.组合优化.md @@ -7,8 +7,11 @@ # 77.组合优化 +## 算法公开课 -**《代码随想录》算法视频公开课:[组合问题的剪枝操作](https://www.bilibili.com/video/BV1wi4y157er),相信结合视频在看本篇题解,更有助于大家对本题的理解**。 +**[《代码随想录》算法视频公开课](https://programmercarl.com/other/gongkaike.html):[组合问题的剪枝操作](https://www.bilibili.com/video/BV1wi4y157er),相信结合视频在看本篇题解,更有助于大家对本题的理解。** + +## 思路 在[回溯算法:求组合问题!](https://programmercarl.com/0077.组合.html)中,我们通过回溯搜索法,解决了n个数中求k个数的组合问题。 @@ -46,7 +49,7 @@ public: }; ``` -# 剪枝优化 +## 剪枝优化 我们说过,回溯法虽然是暴力搜索,但也有时候可以有点剪枝优化一下的。 @@ -135,7 +138,7 @@ public: -# 总结 +## 总结 本篇我们针对求组合问题的回溯法代码做了剪枝优化,这个优化如果不画图的话,其实不好理解,也不好讲清楚。 @@ -143,14 +146,10 @@ public: **就酱,学到了就帮Carl转发一下吧,让更多的同学知道这里!** - - - - ## 其他语言版本 +### Java -Java: ```java class Solution { List> result = new ArrayList<>(); @@ -179,7 +178,8 @@ class Solution { } ``` -Python: +### Python + ```python class Solution: def combine(self, n: int, k: int) -> List[List[int]]: @@ -199,7 +199,8 @@ class Solution: ``` -Go: +### Go + ```Go var ( path []int @@ -227,7 +228,7 @@ func dfs(n int, k int, start int) { } ``` -javaScript: +### JavaScript ```js var combine = function(n, k) { @@ -249,7 +250,7 @@ var combine = function(n, k) { }; ``` -TypeScript: +### TypeScript ```typescript function combine(n: number, k: number): number[][] { @@ -270,7 +271,7 @@ function combine(n: number, k: number): number[][] { }; ``` -Rust: +### Rust ```Rust impl Solution { @@ -296,7 +297,7 @@ impl Solution { } ``` -C: +### C ```c int* path; @@ -351,7 +352,7 @@ int** combine(int n, int k, int* returnSize, int** returnColumnSizes){ } ``` -Swift: +### Swift ```swift func combine(_ n: Int, _ k: Int) -> [[Int]] { @@ -381,7 +382,7 @@ func combine(_ n: Int, _ k: Int) -> [[Int]] { } ``` -Scala: +### Scala ```scala object Solution { @@ -414,3 +415,4 @@ object Solution { + From f30fd2982b532281d156d7c7cd9a9c7471a0a134 Mon Sep 17 00:00:00 2001 From: jinbudaily <18336218010@163.com> Date: Mon, 24 Jul 2023 11:08:32 +0800 Subject: [PATCH 106/122] =?UTF-8?q?=E6=9B=B4=E6=96=B0=200216.=E7=BB=84?= =?UTF-8?q?=E5=90=88=E6=80=BB=E5=92=8CIII=20=E6=8E=92=E7=89=88=E6=A0=BC?= =?UTF-8?q?=E5=BC=8F=E4=BF=AE=E5=A4=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- problems/0077.组合.md | 3 ++- problems/0216.组合总和III.md | 34 ++++++++++++++++------------------ 2 files changed, 18 insertions(+), 19 deletions(-) diff --git a/problems/0077.组合.md b/problems/0077.组合.md index 702ffafe..7d71b517 100644 --- a/problems/0077.组合.md +++ b/problems/0077.组合.md @@ -103,7 +103,7 @@ for (int i = 1; i <= n; i++) { 在[关于回溯算法,你该了解这些!](https://programmercarl.com/回溯算法理论基础.html)中我们提到了回溯法三部曲,那么我们按照回溯法三部曲开始正式讲解代码了。 -## 回溯法三部曲 +### 回溯法三部曲 * 递归函数的返回值以及参数 @@ -744,3 +744,4 @@ object Solution { + diff --git a/problems/0216.组合总和III.md b/problems/0216.组合总和III.md index 319b2eba..4de7dc58 100644 --- a/problems/0216.组合总和III.md +++ b/problems/0216.组合总和III.md @@ -7,8 +7,6 @@ - - > 别看本篇选的是组合总和III,而不是组合总和,本题和上一篇77.组合相比难度刚刚好! # 216.组合总和III @@ -30,12 +28,12 @@ 输入: k = 3, n = 9 输出: [[1,2,6], [1,3,5], [2,3,4]] -# 算法公开课 +## 算法公开课 -**《代码随想录》算法视频公开课:[和组合问题有啥区别?回溯算法如何剪枝?| LeetCode:216.组合总和III](https://www.bilibili.com/video/BV1wg411873x),相信结合视频再看本篇题解,更有助于大家对本题的理解**。 +**[《代码随想录》算法视频公开课](https://programmercarl.com/other/gongkaike.html):[和组合问题有啥区别?回溯算法如何剪枝?| LeetCode:216.组合总和III](https://www.bilibili.com/video/BV1wg411873x),相信结合视频再看本篇题解,更有助于大家对本题的理解**。 -# 思路 +## 思路 本题就是在[1,2,3,4,5,6,7,8,9]这个集合中找到和为n的k个数的组合。 @@ -54,7 +52,7 @@ 图中,可以看出,只有最后取到集合(1,3)和为4 符合条件。 -## 回溯三部曲 +### 回溯三部曲 * **确定递归函数参数** @@ -165,7 +163,7 @@ public: }; ``` -## 剪枝 +### 剪枝 这道题目,剪枝操作其实是很容易想到了,想必大家看上面的树形图的时候已经想到了。 @@ -238,7 +236,7 @@ public: * 时间复杂度: O(n * 2^n) * 空间复杂度: O(n) -# 总结 +## 总结 开篇就介绍了本题与[77.组合](https://programmercarl.com/0077.组合.html)的区别,相对来说加了元素总和的限制,如果做完[77.组合](https://programmercarl.com/0077.组合.html)再做本题在合适不过。 @@ -249,10 +247,10 @@ public: -# 其他语言版本 +## 其他语言版本 -## Java +### Java 模板方法 @@ -358,7 +356,7 @@ class Solution { } ``` -## Python +### Python ```py class Solution: @@ -383,7 +381,7 @@ class Solution: ``` -## Go +### Go 回溯+减枝 @@ -418,7 +416,7 @@ func dfs(k, n int, start int, sum int) { } ``` -## javaScript +### JavaScript ```js /** @@ -455,7 +453,7 @@ var combinationSum3 = function(k, n) { }; ``` -## TypeScript +### TypeScript ```typescript function combinationSum3(k: number, n: number): number[][] { @@ -479,7 +477,7 @@ function combinationSum3(k: number, n: number): number[][] { }; ``` -## Rust +### Rust ```Rust impl Solution { @@ -516,7 +514,7 @@ impl Solution { } ``` -## C +### C ```c int* path; @@ -575,7 +573,7 @@ int** combinationSum3(int k, int n, int* returnSize, int** returnColumnSizes){ } ``` -## Swift +### Swift ```swift func combinationSum3(_ count: Int, _ targetSum: Int) -> [[Int]] { @@ -607,7 +605,7 @@ func combinationSum3(_ count: Int, _ targetSum: Int) -> [[Int]] { } ``` -## Scala +### Scala ```scala object Solution { From 87b215dd2e46588f3c97b25ba4cd2e3b15dbff61 Mon Sep 17 00:00:00 2001 From: jinbudaily <18336218010@163.com> Date: Mon, 24 Jul 2023 11:11:15 +0800 Subject: [PATCH 107/122] =?UTF-8?q?=E6=9B=B4=E6=96=B0=200017.=E7=94=B5?= =?UTF-8?q?=E8=AF=9D=E5=8F=B7=E7=A0=81=E7=9A=84=E5=AD=97=E6=AF=8D=E7=BB=84?= =?UTF-8?q?=E5=90=88=20=E6=8E=92=E7=89=88=E6=A0=BC=E5=BC=8F=E4=BF=AE?= =?UTF-8?q?=E5=A4=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- problems/0017.电话号码的字母组合.md | 36 ++++++++++++++--------------- 1 file changed, 17 insertions(+), 19 deletions(-) diff --git a/problems/0017.电话号码的字母组合.md b/problems/0017.电话号码的字母组合.md index cf5e4520..b3ba1e5e 100644 --- a/problems/0017.电话号码的字母组合.md +++ b/problems/0017.电话号码的字母组合.md @@ -21,12 +21,12 @@ 说明:尽管上面的答案是按字典序排列的,但是你可以任意选择答案输出的顺序。 -# 算法公开课 +## 算法公开课 -**《代码随想录》算法视频公开课:[还得用回溯算法!| LeetCode:17.电话号码的字母组合](https://www.bilibili.com/video/BV1yV4y1V7Ug),相信结合视频再看本篇题解,更有助于大家对本题的理解**。 +**[《代码随想录》算法视频公开课](https://programmercarl.com/other/gongkaike.html)::[还得用回溯算法!| LeetCode:17.电话号码的字母组合](https://www.bilibili.com/video/BV1yV4y1V7Ug),相信结合视频再看本篇题解,更有助于大家对本题的理解**。 -# 思路 +## 思路 从示例上来说,输入"23",最直接的想法就是两层for循环遍历了吧,正好把组合的情况都输出了。 @@ -40,7 +40,7 @@ 2. 两个字母就两个for循环,三个字符我就三个for循环,以此类推,然后发现代码根本写不出来 3. 输入1 * #按键等等异常情况 -## 数字和字母如何映射 +### 数字和字母如何映射 可以使用map或者定义一个二维数组,例如:string letterMap[10],来做映射,我这里定义一个二维数组,代码如下: @@ -59,7 +59,7 @@ const string letterMap[10] = { }; ``` -## 回溯法来解决n个for循环的问题 +### 回溯法来解决n个for循环的问题 对于回溯法还不了解的同学看这篇:[关于回溯算法,你该了解这些!](https://programmercarl.com/回溯算法理论基础.html) @@ -134,9 +134,6 @@ for (int i = 0; i < letters.size(); i++) { **但是要知道会有这些异常,如果是现场面试中,一定要考虑到!** - -## C++代码 - 关键地方都讲完了,按照[关于回溯算法,你该了解这些!](https://programmercarl.com/回溯算法理论基础.html)中的回溯法模板,不难写出如下C++代码: @@ -233,7 +230,7 @@ public: 所以大家可以按照版本一来写就可以了。 -# 总结 +## 总结 本篇将题目的三个要点一一列出,并重点强调了和前面讲解过的[77. 组合](https://programmercarl.com/0077.组合.html)和[216.组合总和III](https://programmercarl.com/0216.组合总和III.html)的区别,本题是多个集合求组合,所以在回溯的搜索过程中,都有一些细节需要注意的。 @@ -241,10 +238,10 @@ public: -# 其他语言版本 +## 其他语言版本 -## Java +### Java ```Java class Solution { @@ -286,7 +283,7 @@ class Solution { } ``` -## Python +### Python 回溯 ```python class Solution: @@ -435,7 +432,7 @@ class Solution: -## Go +### Go 主要在于递归中传递下一个数字 @@ -470,7 +467,7 @@ func dfs(digits string, start int) { } ``` -## javaScript +### JavaScript ```js var letterCombinations = function(digits) { @@ -497,7 +494,7 @@ var letterCombinations = function(digits) { }; ``` -## TypeScript +### TypeScript ```typescript function letterCombinations(digits: string): string[] { @@ -531,7 +528,7 @@ function letterCombinations(digits: string): string[] { }; ``` -## Rust +### Rust ```Rust const map: [&str; 10] = [ @@ -563,7 +560,7 @@ impl Solution { } ``` -## C +### C ```c char* path; @@ -625,7 +622,7 @@ char ** letterCombinations(char * digits, int* returnSize){ } ``` -## Swift +### Swift ```swift func letterCombinations(_ digits: String) -> [String] { @@ -666,7 +663,7 @@ func letterCombinations(_ digits: String) -> [String] { } ``` -## Scala: +### Scala ```scala object Solution { @@ -702,3 +699,4 @@ object Solution { + From 2ed8beef418343adccc7ebc755a8c40159b6fe0d Mon Sep 17 00:00:00 2001 From: jinbudaily <18336218010@163.com> Date: Mon, 24 Jul 2023 11:15:23 +0800 Subject: [PATCH 108/122] =?UTF-8?q?=E6=9B=B4=E6=96=B0=200039.=E7=BB=84?= =?UTF-8?q?=E5=90=88=E6=80=BB=E5=92=8C=20=E6=8E=92=E7=89=88=E6=A0=BC?= =?UTF-8?q?=E5=BC=8F=E4=BF=AE=E5=A4=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- problems/0039.组合总和.md | 33 +++++++++++++++++---------------- 1 file changed, 17 insertions(+), 16 deletions(-) diff --git a/problems/0039.组合总和.md b/problems/0039.组合总和.md index 4d9466c3..2a36ce5a 100644 --- a/problems/0039.组合总和.md +++ b/problems/0039.组合总和.md @@ -39,11 +39,11 @@ candidates 中的数字可以无限制重复被选取。 [3,5] ] -# 算法公开课 +## 算法公开课 -**《代码随想录》算法视频公开课:[Leetcode:39. 组合总和讲解](https://www.bilibili.com/video/BV1KT4y1M7HJ),相信结合视频再看本篇题解,更有助于大家对本题的理解**。 +**[《代码随想录》算法视频公开课](https://programmercarl.com/other/gongkaike.html):[Leetcode:39. 组合总和讲解](https://www.bilibili.com/video/BV1KT4y1M7HJ),相信结合视频再看本篇题解,更有助于大家对本题的理解**。 -# 思路 +## 思路 题目中的**无限制重复被选取,吓得我赶紧想想 出现0 可咋办**,然后看到下面提示:1 <= candidates[i] <= 200,我就放心了。 @@ -57,7 +57,7 @@ candidates 中的数字可以无限制重复被选取。 而在[77.组合](https://programmercarl.com/0077.组合.html)和[216.组合总和III](https://programmercarl.com/0216.组合总和III.html) 中都可以知道要递归K层,因为要取k个元素的组合。 -## 回溯三部曲 +### 回溯三部曲 * 递归函数参数 @@ -156,7 +156,7 @@ public: }; ``` -## 剪枝优化 +### 剪枝优化 在这个树形结构中: @@ -217,7 +217,7 @@ public: * 时间复杂度: O(n * 2^n),注意这只是复杂度的上界,因为剪枝的存在,真实的时间复杂度远小于此 * 空间复杂度: O(target) -# 总结 +## 总结 本题和我们之前讲过的[77.组合](https://programmercarl.com/0077.组合.html)、[216.组合总和III](https://programmercarl.com/0216.组合总和III.html)有两点不同: @@ -238,10 +238,10 @@ public: -# 其他语言版本 +## 其他语言版本 -## Java +### Java ```Java // 剪枝优化 @@ -271,7 +271,7 @@ class Solution { } ``` -## Python +### Python 回溯(版本一) @@ -370,7 +370,7 @@ class Solution: ``` -## Go +### Go 主要在于递归中传递下一个数字 @@ -404,7 +404,7 @@ func dfs(candidates []int, start int, target int) { } ``` -## JavaScript +### JavaScript ```js var combinationSum = function(candidates, target) { @@ -430,7 +430,7 @@ var combinationSum = function(candidates, target) { }; ``` -## TypeScript +### TypeScript ```typescript function combinationSum(candidates: number[], target: number): number[][] { @@ -456,7 +456,7 @@ function combinationSum(candidates: number[], target: number): number[][] { }; ``` -## Rust +### Rust ```Rust impl Solution { @@ -485,7 +485,7 @@ impl Solution { } ``` -## C +### C ```c int* path; @@ -541,7 +541,7 @@ int** combinationSum(int* candidates, int candidatesSize, int target, int* retur } ``` -## Swift +### Swift ```swift func combinationSum(_ candidates: [Int], _ target: Int) -> [[Int]] { @@ -570,7 +570,7 @@ func combinationSum(_ candidates: [Int], _ target: Int) -> [[Int]] { } ``` -## Scala +### Scala ```scala object Solution { @@ -604,3 +604,4 @@ object Solution { + From c3827c43442ad816f4575d7d45958c36dfc92c8a Mon Sep 17 00:00:00 2001 From: jinbudaily <18336218010@163.com> Date: Mon, 24 Jul 2023 11:17:47 +0800 Subject: [PATCH 109/122] =?UTF-8?q?=E6=9B=B4=E6=96=B0=200040.=E7=BB=84?= =?UTF-8?q?=E5=90=88=E6=80=BB=E5=92=8CII=20=E6=8E=92=E7=89=88=E6=A0=BC?= =?UTF-8?q?=E5=BC=8F=E4=BF=AE=E5=A4=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- problems/0040.组合总和II.md | 39 ++++++++++++++++--------------------- 1 file changed, 17 insertions(+), 22 deletions(-) diff --git a/problems/0040.组合总和II.md b/problems/0040.组合总和II.md index 9094020e..33e4a46f 100644 --- a/problems/0040.组合总和II.md +++ b/problems/0040.组合总和II.md @@ -41,13 +41,11 @@ candidates 中的每个数字在每个组合中只能使用一次。 ] ``` -# 算法公开课 +## 算法公开课 -**《代码随想录》算法视频公开课:[回溯算法中的去重,树层去重树枝去重,你弄清楚了没?| LeetCode:40.组合总和II](https://www.bilibili.com/video/BV12V4y1V73A),相信结合视频再看本篇题解,更有助于大家对本题的理解**。 +**[《代码随想录》算法视频公开课](https://programmercarl.com/other/gongkaike.html):[回溯算法中的去重,树层去重树枝去重,你弄清楚了没?| LeetCode:40.组合总和II](https://www.bilibili.com/video/BV12V4y1V73A),相信结合视频再看本篇题解,更有助于大家对本题的理解**。 - - -# 思路 +## 思路 这道题目和[39.组合总和](https://programmercarl.com/0039.组合总和.html)如下区别: @@ -86,7 +84,7 @@ candidates 中的每个数字在每个组合中只能使用一次。 可以看到图中,每个节点相对于 [39.组合总和](https://mp.weixin.qq.com/s/FLg8G6EjVcxBjwCbzpACPw)我多加了used数组,这个used数组下面会重点介绍。 -## 回溯三部曲 +### 回溯三部曲 * **递归函数参数** @@ -217,7 +215,7 @@ public: * 时间复杂度: O(n * 2^n) * 空间复杂度: O(n) -## 补充 +### 补充 这里直接用startIndex来去重也是可以的, 就不用used数组了。 @@ -257,7 +255,7 @@ public: ``` -# 总结 +## 总结 本题同样是求组合总和,但就是因为其数组candidates有重复元素,而要求不能有重复的组合,所以相对于[39.组合总和](https://programmercarl.com/0039.组合总和.html)难度提升了不少。 @@ -265,14 +263,10 @@ public: 所以Carl有必要把去重的这块彻彻底底的给大家讲清楚,**就连“树层去重”和“树枝去重”都是我自创的词汇,希望对大家理解有帮助!** +## 其他语言版本 - - -# 其他语言版本 - - -## Java +### Java **使用标记数组** ```Java class Solution { @@ -355,7 +349,7 @@ class Solution { } ``` -## Python +### Python 回溯 ```python class Solution: @@ -442,7 +436,7 @@ class Solution: self.combinationSumHelper(candidates, target - candidates[i], i + 1, path, results) path.pop() ``` -## Go +### Go 主要在于如何在回溯中去重 **使用used数组** @@ -518,7 +512,7 @@ func dfs(candidates []int, start int, target int) { } } ``` -## javaScript +### JavaScript ```js /** @@ -588,7 +582,7 @@ var combinationSum2 = function(candidates, target) { }; ``` -## TypeScript +### TypeScript ```typescript function combinationSum2(candidates: number[], target: number): number[][] { @@ -619,7 +613,7 @@ function combinationSum2(candidates: number[], target: number): number[][] { }; ``` -## Rust +### Rust ```Rust impl Solution { @@ -654,7 +648,7 @@ impl Solution { } ``` -## C +### C ```c int* path; @@ -716,7 +710,7 @@ int** combinationSum2(int* candidates, int candidatesSize, int target, int* retu } ``` -## Swift +### Swift ```swift func combinationSum2(_ candidates: [Int], _ target: Int) -> [[Int]] { @@ -749,7 +743,7 @@ func combinationSum2(_ candidates: [Int], _ target: Int) -> [[Int]] { ``` -## Scala +### Scala ```scala object Solution { @@ -784,3 +778,4 @@ object Solution { + From 7bd8751a0cf255e17652065d4b1894344032ceb0 Mon Sep 17 00:00:00 2001 From: jinbudaily <18336218010@163.com> Date: Mon, 24 Jul 2023 14:07:54 +0800 Subject: [PATCH 110/122] =?UTF-8?q?=E6=9B=B4=E6=96=B0=200131.=E5=88=86?= =?UTF-8?q?=E5=89=B2=E5=9B=9E=E6=96=87=E4=B8=B2=20=E6=8E=92=E7=89=88?= =?UTF-8?q?=E6=A0=BC=E5=BC=8F=E6=9B=B4=E6=96=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- problems/0131.分割回文串.md | 37 ++++++++++++++++++------------------- 1 file changed, 18 insertions(+), 19 deletions(-) diff --git a/problems/0131.分割回文串.md b/problems/0131.分割回文串.md index 92fed58a..ca73e9f7 100644 --- a/problems/0131.分割回文串.md +++ b/problems/0131.分割回文串.md @@ -23,12 +23,12 @@ ["a","a","b"] ] -# 算法公开课 +## 算法公开课 -**《代码随想录》算法视频公开课:[131.分割回文串](https://www.bilibili.com/video/BV1c54y1e7k6),相信结合视频再看本篇题解,更有助于大家对本题的理解**。 +**[《代码随想录》算法视频公开课](https://programmercarl.com/other/gongkaike.html):[131.分割回文串](https://www.bilibili.com/video/BV1c54y1e7k6),相信结合视频再看本篇题解,更有助于大家对本题的理解**。 -# 思路 +## 思路 本题这涉及到两个关键问题: @@ -58,7 +58,7 @@ 此时可以发现,切割问题的回溯搜索的过程和组合问题的回溯搜索的过程是差不多的。 -## 回溯三部曲 +### 回溯三部曲 * 递归函数参数 @@ -124,7 +124,7 @@ for (int i = startIndex; i < s.size(); i++) { **注意切割过的位置,不能重复切割,所以,backtracking(s, i + 1); 传入下一层的起始位置为i + 1**。 -## 判断回文子串 +### 判断回文子串 最后我们看一下回文子串要如何判断了,判断一个字符串是否是回文。 @@ -147,8 +147,6 @@ for (int i = startIndex; i < s.size(); i++) { 此时关键代码已经讲解完毕,整体代码如下(详细注释了) -## C++整体代码 - 根据Carl给出的回溯算法模板: ```CPP @@ -212,7 +210,7 @@ public: * 时间复杂度: O(n * 2^n) * 空间复杂度: O(n^2) -# 优化 +## 优化 上面的代码还存在一定的优化空间, 在于如何更高效的计算一个子字符串是否是回文字串。上述代码```isPalindrome```函数运用双指针的方法来判定对于一个字符串```s```, 给定起始下标和终止下标, 截取出的子字符串是否是回文字串。但是其中有一定的重复计算存在: @@ -272,7 +270,7 @@ public: ``` -# 总结 +## 总结 这道题目在leetcode上是中等,但可以说是hard的题目了,但是代码其实就是按照模板的样子来的。 @@ -306,10 +304,10 @@ public: -# 其他语言版本 +## 其他语言版本 -## Java +### Java ```Java class Solution { List> lists = new ArrayList<>(); @@ -351,7 +349,7 @@ class Solution { } ``` -## Python +### Python 回溯 基本版 ```python class Solution: @@ -473,7 +471,7 @@ class Solution: return all(s[i] == s[len(s) - 1 - i] for i in range(len(s) // 2)) ``` -## Go +### Go ```go var ( path []string // 放已经回文的子串 @@ -512,7 +510,7 @@ func isPalindrome(s string) bool { } ``` -## javaScript +### JavaScript ```js /** @@ -545,7 +543,7 @@ var partition = function(s) { }; ``` -## TypeScript +### TypeScript ```typescript function partition(s: string): string[][] { @@ -582,7 +580,7 @@ function partition(s: string): string[][] { }; ``` -## C +### C ```c char** path; @@ -679,7 +677,7 @@ char*** partition(char* s, int* returnSize, int** returnColumnSizes){ } ``` -## Swift +### Swift ```swift func partition(_ s: String) -> [[String]] { @@ -719,7 +717,7 @@ func partition(_ s: String) -> [[String]] { } ``` -## Rust +### Rust **回溯+函数判断回文串** ```Rust @@ -808,7 +806,7 @@ impl Solution { ``` -## Scala +### Scala ```scala object Solution { @@ -855,3 +853,4 @@ object Solution { + From 6f711891ba9df855e68147bc0f609753bd705cf7 Mon Sep 17 00:00:00 2001 From: jinbudaily <18336218010@163.com> Date: Mon, 24 Jul 2023 14:11:47 +0800 Subject: [PATCH 111/122] =?UTF-8?q?=E6=9B=B4=E6=96=B0=200093.=E5=A4=8D?= =?UTF-8?q?=E5=8E=9FIP=E5=9C=B0=E5=9D=80=20=E6=8E=92=E7=89=88=E6=A0=BC?= =?UTF-8?q?=E5=BC=8F=E4=BF=AE=E5=A4=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- problems/0093.复原IP地址.md | 41 +++++++++++++++---------------------- 1 file changed, 17 insertions(+), 24 deletions(-) diff --git a/problems/0093.复原IP地址.md b/problems/0093.复原IP地址.md index 55e57dde..59cd92da 100644 --- a/problems/0093.复原IP地址.md +++ b/problems/0093.复原IP地址.md @@ -40,16 +40,12 @@ * 0 <= s.length <= 3000 * s 仅由数字组成 -# 算法公开课 +## 算法公开课 -**《代码随想录》算法视频公开课:[93.复原IP地址](https://www.bilibili.com/video/BV1XP4y1U73i/),相信结合视频再看本篇题解,更有助于大家对本题的理解**。 - -# 算法公开课 - -**《代码随想录》算法视频公开课:[回溯算法如何分割字符串并判断是合法IP?| LeetCode:93.复原IP地址](https://www.bilibili.com/video/BV1XP4y1U73i/),相信结合视频再看本篇题解,更有助于大家对本题的理解**。 +**[《代码随想录》算法视频公开课](https://programmercarl.com/other/gongkaike.html):[回溯算法如何分割字符串并判断是合法IP?| LeetCode:93.复原IP地址](https://www.bilibili.com/video/BV1XP4y1U73i/),相信结合视频再看本篇题解,更有助于大家对本题的理解**。 -# 思路 +## 思路 做这道题目之前,最好先把[131.分割回文串](https://programmercarl.com/0131.分割回文串.html)这个做了。 @@ -63,7 +59,7 @@ ![93.复原IP地址](https://code-thinking-1253855093.file.myqcloud.com/pics/20201123203735933.png) -## 回溯三部曲 +### 回溯三部曲 * 递归参数 @@ -134,7 +130,7 @@ for (int i = startIndex; i < s.size(); i++) { } ``` -## 判断子串是否合法 +### 判断子串是否合法 最后就是在写一个判断段位是否是有效段位了。 @@ -169,8 +165,6 @@ bool isValid(const string& s, int start, int end) { } ``` -## C++代码 - 根据[关于回溯算法,你该了解这些!](https://programmercarl.com/回溯算法理论基础.html)给出的回溯算法模板: @@ -247,7 +241,7 @@ public: * 时间复杂度: O(3^4),IP地址最多包含4个数字,每个数字最多有3种可能的分割方式,则搜索树的最大深度为4,每个节点最多有3个子节点。 * 空间复杂度: O(n) -# 总结 +## 总结 在[131.分割回文串](https://programmercarl.com/0131.分割回文串.html)中我列举的分割字符串的难点,本题都覆盖了。 @@ -259,9 +253,9 @@ public: -# 其他语言版本 +## 其他语言版本 -## java +### Java ```java class Solution { @@ -402,7 +396,7 @@ class Solution { ``` -## python +### Python 回溯(版本一) ```python @@ -478,9 +472,7 @@ class Solution: ``` - - -## Go +### Go ```go var ( @@ -517,7 +509,7 @@ func dfs(s string, start int) { } ``` -## JavaScript +### JavaScript ```js /** @@ -547,7 +539,7 @@ var restoreIpAddresses = function(s) { }; ``` -## TypeScript +### TypeScript ```typescript function isValidIpSegment(str: string): boolean { @@ -586,7 +578,7 @@ function restoreIpAddresses(s: string): string[] { }; ``` -## Rust +### Rust ```Rust impl Solution { @@ -643,7 +635,7 @@ impl Solution { } ``` -## C +### C ```c //记录结果 char** result; @@ -719,7 +711,7 @@ char ** restoreIpAddresses(char * s, int* returnSize){ } ``` -## Swift +### Swift ```swift // 判断区间段是否合法 @@ -766,7 +758,7 @@ func restoreIpAddresses(_ s: String) -> [String] { } ``` -## Scala +### Scala ```scala object Solution { @@ -813,3 +805,4 @@ object Solution { + From 92695ceeddbc3b9c39d367bd522a44e1b37502b1 Mon Sep 17 00:00:00 2001 From: jinbudaily <18336218010@163.com> Date: Mon, 24 Jul 2023 14:16:33 +0800 Subject: [PATCH 112/122] =?UTF-8?q?=E6=9B=B4=E6=96=B0=200078.=E5=AD=90?= =?UTF-8?q?=E9=9B=86=E9=97=AE=E9=A2=98=20=E6=8E=92=E7=89=88=E6=A0=BC?= =?UTF-8?q?=E5=BC=8F=E4=BF=AE=E5=A4=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- problems/0078.子集.md | 33 ++++++++++++++++----------------- 1 file changed, 16 insertions(+), 17 deletions(-) diff --git a/problems/0078.子集.md b/problems/0078.子集.md index 21009f6a..5f3654de 100644 --- a/problems/0078.子集.md +++ b/problems/0078.子集.md @@ -27,12 +27,12 @@   [] ] -# 算法公开课 +## 算法公开课 -**《代码随想录》算法视频公开课:[回溯算法解决子集问题,树上节点都是目标集和! | LeetCode:78.子集](https://www.bilibili.com/video/BV1U84y1q7Ci),相信结合视频再看本篇题解,更有助于大家对本题的理解**。 +**[《代码随想录》算法视频公开课](https://programmercarl.com/other/gongkaike.html):[回溯算法解决子集问题,树上节点都是目标集和! | LeetCode:78.子集](https://www.bilibili.com/video/BV1U84y1q7Ci),相信结合视频再看本篇题解,更有助于大家对本题的理解**。 -# 思路 +## 思路 求子集问题和[77.组合](https://programmercarl.com/0077.组合.html)和[131.分割回文串](https://programmercarl.com/0131.分割回文串.html)又不一样了。 @@ -52,7 +52,7 @@ 从图中红线部分,可以看出**遍历这个树的时候,把所有节点都记录下来,就是要求的子集集合**。 -## 回溯三部曲 +### 回溯三部曲 * 递归函数参数 @@ -102,8 +102,6 @@ for (int i = startIndex; i < nums.size(); i++) { } ``` -## C++代码 - 根据[关于回溯算法,你该了解这些!](https://programmercarl.com/回溯算法理论基础.html)给出的回溯算法模板: ``` @@ -158,7 +156,7 @@ public: 并不会,因为每次递归的下一层就是从i+1开始的。 -# 总结 +## 总结 相信大家经过了 * 组合问题: @@ -178,10 +176,10 @@ public: **而组合问题、分割问题是收集树形结构中叶子节点的结果**。 -# 其他语言版本 +## 其他语言版本 -## Java +### Java ```java class Solution { List> result = new ArrayList<>();// 存放符合条件结果的集合 @@ -205,7 +203,7 @@ class Solution { } ``` -## Python +### Python ```python class Solution: def subsets(self, nums): @@ -224,7 +222,7 @@ class Solution: path.pop() ``` -## Go +### Go ```Go var ( path []int @@ -248,7 +246,7 @@ func dfs(nums []int, start int) { } ``` -## Javascript +### Javascript ```Javascript var subsets = function(nums) { @@ -267,7 +265,7 @@ var subsets = function(nums) { }; ``` -## TypeScript +### TypeScript ```typescript function subsets(nums: number[]): number[][] { @@ -287,7 +285,7 @@ function subsets(nums: number[]): number[][] { }; ``` -## Rust +### Rust ```Rust impl Solution { @@ -311,7 +309,7 @@ impl Solution { } ``` -## C +### C ```c int* path; @@ -369,7 +367,7 @@ int** subsets(int* nums, int numsSize, int* returnSize, int** returnColumnSizes) } ``` -## Swift +### Swift ```swift func subsets(_ nums: [Int]) -> [[Int]] { @@ -392,7 +390,7 @@ func subsets(_ nums: [Int]) -> [[Int]] { } ``` -## Scala +### Scala 思路一: 使用本题解思路 @@ -451,3 +449,4 @@ object Solution { + From cbec2c04ed9c107921834854f41b36dfd9cab785 Mon Sep 17 00:00:00 2001 From: jinbudaily <18336218010@163.com> Date: Mon, 24 Jul 2023 14:50:02 +0800 Subject: [PATCH 113/122] =?UTF-8?q?=E6=9B=B4=E6=96=B0=200090.=E5=AD=90?= =?UTF-8?q?=E9=9B=86II=20=E6=8E=92=E7=89=88=E6=A0=BC=E5=BC=8F=E6=9B=B4?= =?UTF-8?q?=E6=96=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- problems/0090.子集II.md | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/problems/0090.子集II.md b/problems/0090.子集II.md index 3238ee52..88c8bdad 100644 --- a/problems/0090.子集II.md +++ b/problems/0090.子集II.md @@ -3,8 +3,6 @@

参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!

- - # 90.子集II [力扣题目链接](https://leetcode.cn/problems/subsets-ii/) @@ -25,9 +23,9 @@ [] ] -# 算法公开课 +## 算法公开课 -**《代码随想录》算法视频公开课:[回溯算法解决子集问题,如何去重?| LeetCode:90.子集II](https://www.bilibili.com/video/BV1vm4y1F71J/),相信结合视频再看本篇题解,更有助于大家对本题的理解**。 +**[《代码随想录》算法视频公开课](https://programmercarl.com/other/gongkaike.html):[回溯算法解决子集问题,如何去重?| LeetCode:90.子集II](https://www.bilibili.com/video/BV1vm4y1F71J/),相信结合视频再看本篇题解,更有助于大家对本题的理解**。 ## 思路 @@ -240,7 +238,7 @@ class Solution { -#### Python3 +### Python3 回溯 利用used数组去重 ```python @@ -646,3 +644,4 @@ object Solution { + From 322f817666b8bd7c65477a9168bb1db5c4f16410 Mon Sep 17 00:00:00 2001 From: jinbudaily <18336218010@163.com> Date: Mon, 24 Jul 2023 14:51:29 +0800 Subject: [PATCH 114/122] =?UTF-8?q?=E6=9B=B4=E6=96=B0=200491.=E9=80=92?= =?UTF-8?q?=E5=A2=9E=E5=AD=90=E5=BA=8F=E5=88=97=20=E6=8E=92=E7=89=88?= =?UTF-8?q?=E6=A0=BC=E5=BC=8F=E4=BF=AE=E5=A4=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- problems/0491.递增子序列.md | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/problems/0491.递增子序列.md b/problems/0491.递增子序列.md index 4b21008e..e2011372 100644 --- a/problems/0491.递增子序列.md +++ b/problems/0491.递增子序列.md @@ -23,9 +23,9 @@ * 数组中的整数范围是 [-100,100]。 * 给定数组中可能包含重复数字,相等的数字应该被视为递增的一种情况。 -# 算法公开课 +## 算法公开课 -**《代码随想录》算法视频公开课:[回溯算法精讲,树层去重与树枝去重 | LeetCode:491.递增子序列](https://www.bilibili.com/video/BV1EG4y1h78v/),相信结合视频再看本篇题解,更有助于大家对本题的理解**。 +**[《代码随想录》算法视频公开课](https://programmercarl.com/other/gongkaike.html):[回溯算法精讲,树层去重与树枝去重 | LeetCode:491.递增子序列](https://www.bilibili.com/video/BV1EG4y1h78v/),相信结合视频再看本篇题解,更有助于大家对本题的理解**。 ## 思路 @@ -619,4 +619,3 @@ object Solution { - From f08c25631fc39152caa4d3f78ffb6b0d02c3f2e5 Mon Sep 17 00:00:00 2001 From: jinbudaily <18336218010@163.com> Date: Mon, 24 Jul 2023 14:54:15 +0800 Subject: [PATCH 115/122] =?UTF-8?q?=E6=9B=B4=E6=96=B0=20046.=E5=85=A8?= =?UTF-8?q?=E6=8E=92=E5=88=97=20=E6=8E=92=E7=89=88=E6=A0=BC=E5=BC=8F?= =?UTF-8?q?=E4=BF=AE=E5=A4=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- problems/0046.全排列.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/problems/0046.全排列.md b/problems/0046.全排列.md index de1af642..1f5263a7 100644 --- a/problems/0046.全排列.md +++ b/problems/0046.全排列.md @@ -24,9 +24,9 @@ ] -# 算法公开课 +## 算法公开课 -**《代码随想录》算法视频公开课:[组合与排列的区别,回溯算法求解的时候,有何不同?| LeetCode:46.全排列](https://www.bilibili.com/video/BV19v4y1S79W/),相信结合视频再看本篇题解,更有助于大家对本题的理解**。 +**[《代码随想录》算法视频公开课](https://programmercarl.com/other/gongkaike.html):[组合与排列的区别,回溯算法求解的时候,有何不同?| LeetCode:46.全排列](https://www.bilibili.com/video/BV19v4y1S79W/),相信结合视频再看本篇题解,更有助于大家对本题的理解**。 ## 思路 @@ -491,3 +491,4 @@ object Solution { + From f57b19df94a1ed5122571e4482796a8594053af6 Mon Sep 17 00:00:00 2001 From: jinbudaily <18336218010@163.com> Date: Mon, 24 Jul 2023 14:55:37 +0800 Subject: [PATCH 116/122] =?UTF-8?q?=E6=9B=B4=E6=96=B0=200047.=E5=85=A8?= =?UTF-8?q?=E6=8E=92=E5=88=97II=20=E6=8E=92=E7=89=88=E6=A0=BC=E5=BC=8F?= =?UTF-8?q?=E4=BF=AE=E5=A4=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- problems/0047.全排列II.md | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/problems/0047.全排列II.md b/problems/0047.全排列II.md index afede33a..4fed8a5c 100644 --- a/problems/0047.全排列II.md +++ b/problems/0047.全排列II.md @@ -31,9 +31,9 @@ * 1 <= nums.length <= 8 * -10 <= nums[i] <= 10 -# 算法公开课 +## 算法公开课 -**《代码随想录》算法视频公开课:[回溯算法求解全排列,如何去重?| LeetCode:47.全排列 II](https://www.bilibili.com/video/BV1R84y1i7Tm/),相信结合视频再看本篇题解,更有助于大家对本题的理解**。 +**[《代码随想录》算法视频公开课](https://programmercarl.com/other/gongkaike.html):[回溯算法求解全排列,如何去重?| LeetCode:47.全排列 II](https://www.bilibili.com/video/BV1R84y1i7Tm/),相信结合视频再看本篇题解,更有助于大家对本题的理解**。 ## 思路 @@ -58,7 +58,7 @@ 在[46.全排列](https://programmercarl.com/0046.全排列.html)中已经详细讲解了排列问题的写法,在[40.组合总和II](https://programmercarl.com/0040.组合总和II.html) 、[90.子集II](https://programmercarl.com/0090.子集II.html)中详细讲解了去重的写法,所以这次我就不用回溯三部曲分析了,直接给出代码,如下: -## C++代码 + ```CPP class Solution { @@ -170,7 +170,7 @@ if (i > 0 && nums[i] == nums[i - 1] && used[i - 1] == true) { if (i > 0 && nums[i] == nums[i - 1]) { continue; } -``` +``` 其实并不行,一定要加上 `used[i - 1] == false`或者`used[i - 1] == true`,因为 used[i - 1] 要一直是 true 或者一直是false 才可以,而不是 一会是true 一会又是false。 所以这个条件要写上。 @@ -179,7 +179,7 @@ if (i > 0 && nums[i] == nums[i - 1]) { ## 其他语言版本 -### java +### Java ```java class Solution { @@ -221,7 +221,7 @@ class Solution { } ``` -### python +Python ```python class Solution: @@ -526,3 +526,4 @@ object Solution { + From d9fc7a2d0e76b3439f68a165bcfe98553af4b7dd Mon Sep 17 00:00:00 2001 From: jinbudaily <18336218010@163.com> Date: Mon, 24 Jul 2023 14:59:16 +0800 Subject: [PATCH 117/122] =?UTF-8?q?=E6=9B=B4=E6=96=B0=20=E5=9B=9E=E6=BA=AF?= =?UTF-8?q?=E7=AE=97=E6=B3=95=E5=8E=BB=E9=87=8D=E9=97=AE=E9=A2=98=E7=9A=84?= =?UTF-8?q?=E5=8F=A6=E4=B8=80=E7=A7=8D=E5=86=99=E6=B3=95=20=E6=8E=92?= =?UTF-8?q?=E7=89=88=E6=A0=BC=E5=BC=8F=E4=BF=AE=E5=A4=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- problems/回溯算法去重问题的另一种写法.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/problems/回溯算法去重问题的另一种写法.md b/problems/回溯算法去重问题的另一种写法.md index 4e09b925..2be79805 100644 --- a/problems/回溯算法去重问题的另一种写法.md +++ b/problems/回溯算法去重问题的另一种写法.md @@ -246,8 +246,7 @@ used数组可是全局变量,每层与每层之间公用一个used数组,所 ## 其他语言版本 - -Java: +### Java **47.全排列II** @@ -350,7 +349,7 @@ class Solution { } } ``` -Python: +### Python **90.子集II** @@ -432,7 +431,7 @@ class Solution: ``` -JavaScript: +### JavaScript **90.子集II** @@ -510,7 +509,7 @@ function permuteUnique(nums) { }; ``` -TypeScript: +### TypeScript **90.子集II** @@ -592,7 +591,7 @@ function permuteUnique(nums: number[]): number[][] { }; ``` -Rust: +### Rust **90.子集II**: @@ -713,3 +712,4 @@ impl Solution { + From 42c1bd94ab1bddac9f258730d26275ff6cfeeeec Mon Sep 17 00:00:00 2001 From: jinbudaily <18336218010@163.com> Date: Mon, 24 Jul 2023 15:03:21 +0800 Subject: [PATCH 118/122] =?UTF-8?q?=E6=9B=B4=E6=96=B0=200332.=E9=87=8D?= =?UTF-8?q?=E6=96=B0=E5=AE=89=E6=8E=92=E8=A1=8C=E7=A8=8B=20=E6=8E=92?= =?UTF-8?q?=E7=89=88=E6=A0=BC=E5=BC=8F=E4=BF=AE=E5=A4=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- problems/0332.重新安排行程.md | 29 ++++++++++++++++------------- 1 file changed, 16 insertions(+), 13 deletions(-) diff --git a/problems/0332.重新安排行程.md b/problems/0332.重新安排行程.md index fa6414e9..3798b48d 100644 --- a/problems/0332.重新安排行程.md +++ b/problems/0332.重新安排行程.md @@ -29,9 +29,11 @@ * 输出:["JFK","ATL","JFK","SFO","ATL","SFO"] * 解释:另一种有效的行程是 ["JFK","SFO","ATL","JFK","ATL","SFO"]。但是它自然排序更大更靠后。 -## 思路 +## 算法公开课 -**如果对回溯算法基础还不了解的话,我还特意录制了一期视频:[带你学透回溯算法(理论篇)](https://www.bilibili.com/video/BV1cy4y167mM/)** 可以结合题解和视频一起看,希望对大家理解回溯算法有所帮助。 +**如果对回溯算法基础还不了解的话,我还特意录制了一期视频,[《代码随想录》算法视频公开课](https://programmercarl.com/other/gongkaike.html):[带你学透回溯算法(理论篇)](https://www.bilibili.com/video/BV1cy4y167mM/)** 可以结合题解和视频一起看,希望对大家理解回溯算法有所帮助。 + +## 思路 这道题目还是很难的,之前我们用回溯法解决了如下问题:[组合问题](https://programmercarl.com/0077.组合.html),[分割问题](https://programmercarl.com/0093.复原IP地址.html),[子集问题](https://programmercarl.com/0078.子集.html),[排列问题](https://programmercarl.com/0046.全排列.html)。 @@ -53,7 +55,7 @@ 针对以上问题我来逐一解答! -## 如何理解死循环 +### 如何理解死循环 对于死循环,我来举一个有重复机场的例子: @@ -61,7 +63,7 @@ 为什么要举这个例子呢,就是告诉大家,出发机场和到达机场也会重复的,**如果在解题的过程中没有对集合元素处理好,就会死循环。** -## 该记录映射关系 +### 该记录映射关系 有多种解法,字母序靠前排在前面,让很多同学望而退步,如何该记录映射关系呢 ? @@ -90,7 +92,7 @@ unordered_map> targets:unordered_map<出发机场, ma **相当于说我不删,我就做一个标记!** -## 回溯法 +### 回溯法 这道题目我使用回溯法,那么下面按照我总结的回溯模板来: @@ -260,8 +262,8 @@ for (pairtarget : targets[result[result.size() - 1]]) ## 其他语言版本 -### java - +### Java + ```java class Solution { private LinkedList res; @@ -346,7 +348,7 @@ class Solution { } ``` -### python +### Python 回溯 使用used数组 ```python @@ -406,7 +408,7 @@ class Solution: path.pop() # 移除目的地 return False # 没有找到有效行程 -``` +``` 回溯 使用字典 逆序 ```python from collections import defaultdict @@ -430,8 +432,8 @@ class Solution: self.backtracking(next_airport, targets, result) # 递归调用回溯函数进行深度优先搜索 result.append(airport) # 将当前机场添加到行程路径中 ``` - -### GO + +### Go ```go type pair struct { target string @@ -577,7 +579,7 @@ function findItinerary(tickets: string[][]): string[] { }; ``` -### C语言 +### C ```C char **result; @@ -638,7 +640,7 @@ char ** findItinerary(char *** tickets, int ticketsSize, int* ticketsColSize, in return result; } ``` - + ### Swift 直接迭代tickets数组: @@ -791,3 +793,4 @@ impl Solution { + From f58a35db26a0fa4f4b4ae552e3713392b9e1d193 Mon Sep 17 00:00:00 2001 From: jinbudaily <18336218010@163.com> Date: Mon, 24 Jul 2023 15:04:28 +0800 Subject: [PATCH 119/122] =?UTF-8?q?=E6=9B=B4=E6=96=B0=200051.N=E7=9A=87?= =?UTF-8?q?=E5=90=8E=20=E6=8E=92=E7=89=88=E6=A0=BC=E5=BC=8F=E4=BF=AE?= =?UTF-8?q?=E5=A4=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- problems/0051.N皇后.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/problems/0051.N皇后.md b/problems/0051.N皇后.md index 13cdafb8..6bc4fa78 100644 --- a/problems/0051.N皇后.md +++ b/problems/0051.N皇后.md @@ -28,9 +28,9 @@ n 皇后问题 研究的是如何将 n 个皇后放置在 n×n 的棋盘上, * 输入:n = 1 * 输出:[["Q"]] -# 算法公开课 +## 算法公开课 -**《代码随想录》算法视频公开课:[这就是传说中的N皇后? 回溯算法安排!| LeetCode:51.N皇后](https://www.bilibili.com/video/BV1Rd4y1c7Bq/),相信结合视频再看本篇题解,更有助于大家对本题的理解**。 +**[《代码随想录》算法视频公开课](https://programmercarl.com/other/gongkaike.html):[这就是传说中的N皇后? 回溯算法安排!| LeetCode:51.N皇后](https://www.bilibili.com/video/BV1Rd4y1c7Bq/),相信结合视频再看本篇题解,更有助于大家对本题的理解**。 ## 思路 @@ -864,3 +864,4 @@ object Solution { + From dacd87b009f8a106172c4e07853bdf2b3aaf664f Mon Sep 17 00:00:00 2001 From: jinbudaily <18336218010@163.com> Date: Mon, 24 Jul 2023 15:05:52 +0800 Subject: [PATCH 120/122] =?UTF-8?q?=E6=9B=B4=E6=96=B0=200051.N=E7=9A=87?= =?UTF-8?q?=E5=90=8EII=20=E6=8E=92=E7=89=88=E6=A0=BC=E5=BC=8F=E4=BF=AE?= =?UTF-8?q?=E5=A4=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- problems/0052.N皇后II.md | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/problems/0052.N皇后II.md b/problems/0052.N皇后II.md index 90b920ba..ac774c83 100644 --- a/problems/0052.N皇后II.md +++ b/problems/0052.N皇后II.md @@ -43,13 +43,11 @@ n 皇后问题研究的是如何将 n 个皇后放置在 n×n 的棋盘上,并   ".Q.."] ] -# 思路 +## 思路 详看:[51.N皇后](https://mp.weixin.qq.com/s/lU_QwCMj6g60nh8m98GAWg) ,基本没有区别 -# C++代码 - ```CPP class Solution { private: @@ -100,8 +98,9 @@ public: }; ``` -# 其他语言补充 -JavaScript +## 其他语言补充 +### JavaScript + ```javascript var totalNQueens = function(n) { let count = 0; @@ -146,7 +145,7 @@ var totalNQueens = function(n) { }; ``` -TypeScript: +### TypeScript ```typescript // 0-该格为空,1-该格有皇后 @@ -199,7 +198,7 @@ function checkValid(chess: GridStatus[][], i: number, j: number, n: number): boo } ``` -C +### C ```c //path[i]为在i行,path[i]列上存在皇后 @@ -258,7 +257,8 @@ int totalNQueens(int n){ return answer; } ``` -Java +### Java + ```java class Solution { int count = 0; @@ -310,4 +310,3 @@ class Solution { - From 028bfdc662a56e8f0c7ff17bd743a2d21fe0f016 Mon Sep 17 00:00:00 2001 From: jinbudaily <18336218010@163.com> Date: Mon, 24 Jul 2023 15:11:08 +0800 Subject: [PATCH 121/122] =?UTF-8?q?=E6=9B=B4=E6=96=B0=200037.=E8=A7=A3?= =?UTF-8?q?=E6=95=B0=E7=8B=AC=20=E6=8E=92=E7=89=88=E6=A0=BC=E5=BC=8F?= =?UTF-8?q?=E4=BF=AE=E5=A4=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- problems/0037.解数独.md | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/problems/0037.解数独.md b/problems/0037.解数独.md index 6edd3c5b..1763063e 100644 --- a/problems/0037.解数独.md +++ b/problems/0037.解数独.md @@ -6,8 +6,7 @@

参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!

- -如果对回溯法理论还不清楚的同学,可以先看这个视频[视频来了!!带你学透回溯算法(理论篇)](https://mp.weixin.qq.com/s/wDd5azGIYWjbU0fdua_qBg) +> 如果对回溯法理论还不清楚的同学,可以先看这个视频[视频来了!!带你学透回溯算法(理论篇)](https://mp.weixin.qq.com/s/wDd5azGIYWjbU0fdua_qBg) # 37. 解数独 @@ -35,11 +34,9 @@ * 你可以假设给定的数独只有唯一解。 * 给定数独永远是 9x9 形式的。 -# 算法公开课 - -**《代码随想录》算法视频公开课:[回溯算法二维递归?解数独不过如此!| LeetCode:37. 解数独](https://www.bilibili.com/video/BV1TW4y1471V/),相信结合视频再看本篇题解,更有助于大家对本题的理解**。 - +## 算法公开课 +**[《代码随想录》算法视频公开课](https://programmercarl.com/other/gongkaike.html):[回溯算法二维递归?解数独不过如此!| LeetCode:37. 解数独](https://www.bilibili.com/video/BV1TW4y1471V/),相信结合视频再看本篇题解,更有助于大家对本题的理解**。 ## 思路 @@ -764,3 +761,4 @@ object Solution { + From 93cba02a128b8aa9cd5982d36537a802dda03262 Mon Sep 17 00:00:00 2001 From: jinbudaily <18336218010@163.com> Date: Mon, 24 Jul 2023 15:15:04 +0800 Subject: [PATCH 122/122] =?UTF-8?q?=E6=9B=B4=E6=96=B0=20=E5=9B=9E=E6=BA=AF?= =?UTF-8?q?=E6=80=BB=E7=BB=93=20=E6=8E=92=E7=89=88=E6=A0=BC=E5=BC=8F?= =?UTF-8?q?=E4=BF=AE=E5=A4=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- problems/回溯总结.md | 49 +++++++++++++++++++++++--------------------- 1 file changed, 26 insertions(+), 23 deletions(-) diff --git a/problems/回溯总结.md b/problems/回溯总结.md index 21d78bc2..f2e46829 100644 --- a/problems/回溯总结.md +++ b/problems/回溯总结.md @@ -8,7 +8,9 @@ > 20张树形结构图、14道精选回溯题目,21篇回溯法精讲文章,由浅入深,一气呵成,这是全网最强回溯算法总结! -# 回溯法理论基础 +# 回溯总结篇 + +## 回溯法理论基础 转眼间[「代码随想录」](https://img-blog.csdnimg.cn/20200815195519696.png)里已经分享连续讲解了21天的回溯算法,是时候做一个大总结了,本篇高能,需要花费很大的精力来看! @@ -51,10 +53,10 @@ void backtracking(参数) { **事实证明这个模板会伴随整个回溯法系列!** -# 组合问题 - ## 组合问题 +### 组合问题 + 在[回溯算法:求组合问题!](https://programmercarl.com/0077.组合.html)中,我们开始用回溯法解决第一道题目:组合问题。 我在文中开始的时候给大家列举k层for循环例子,进而得出都是同样是暴力解法,为什么要用回溯法! @@ -82,9 +84,9 @@ void backtracking(参数) { **在for循环上做剪枝操作是回溯法剪枝的常见套路!** 后面的题目还会经常用到。 -## 组合总和 +### 组合总和 -### 组合总和(一) +#### 组合总和(一) 在[回溯算法:求组合总和!](https://programmercarl.com/0216.组合总和III.html)中,相当于 [回溯算法:求组合问题!](https://programmercarl.com/0077.组合.html)加了一个元素总和的限制。 @@ -99,7 +101,7 @@ void backtracking(参数) { 所以剪枝的代码可以在for循环加上 `i <= 9 - (k - path.size()) + 1` 的限制! -### 组合总和(二) +#### 组合总和(二) 在[回溯算法:求组合总和(二)](https://programmercarl.com/0039.组合总和.html)中讲解的组合总和问题,和[回溯算法:求组合问题!](https://programmercarl.com/0077.组合.html),[回溯算法:求组合总和!](https://programmercarl.com/0216.组合总和III.html)和区别是:本题没有数量要求,可以无限重复,但是有总和的限制,所以间接的也是有个数的限制。 @@ -128,7 +130,7 @@ for (int i = startIndex; i < candidates.size() && sum + candidates[i] <= target; ![39.组合总和1](https://code-thinking-1253855093.file.myqcloud.com/pics/20201118202115929.png) -### 组合总和(三) +#### 组合总和(三) 在[回溯算法:求组合总和(三)](https://programmercarl.com/0040.组合总和II.html)中集合元素会有重复,但要求解集不能包含重复的组合。 @@ -151,7 +153,7 @@ for (int i = startIndex; i < candidates.size() && sum + candidates[i] <= target; 对于去重,其实排列和子集问题也是一样的道理。 -## 多个集合求组合 +### 多个集合求组合 在[回溯算法:电话号码的字母组合](https://programmercarl.com/0017.电话号码的字母组合.html)中,开始用多个集合来求组合,还是熟悉的模板题目,但是有一些细节。 @@ -167,7 +169,7 @@ for (int i = startIndex; i < candidates.size() && sum + candidates[i] <= target; 其实本题不算难,但也处处是细节,还是要反复琢磨。 -# 切割问题 +## 切割问题 在[回溯算法:分割回文串](https://programmercarl.com/0131.分割回文串.html)中,我们开始讲解切割问题,虽然最后代码看起来好像是一道模板题,但是从分析到学会套用这个模板,是比较难的。 @@ -192,9 +194,9 @@ for (int i = startIndex; i < candidates.size() && sum + candidates[i] <= target; ![131.分割回文串](https://code-thinking-1253855093.file.myqcloud.com/pics/20201118202448642.png) -# 子集问题 +## 子集问题 -## 子集问题(一) +### 子集问题(一) 在[回溯算法:求子集问题!](https://programmercarl.com/0078.子集.html)中讲解了子集问题,**在树形结构中子集问题是要收集所有节点的结果,而组合问题是收集叶子节点的结果**。 @@ -219,7 +221,7 @@ if (startIndex >= nums.size()) { // 终止条件可以不加 } ``` -## 子集问题(二) +### 子集问题(二) 在[回溯算法:求子集问题(二)](https://programmercarl.com/0090.子集II.html)中,开始针对子集问题进行去重。 @@ -229,7 +231,7 @@ if (startIndex >= nums.size()) { // 终止条件可以不加 ![90.子集II](https://code-thinking-1253855093.file.myqcloud.com/pics/2020111217110449.png) -## 递增子序列 +### 递增子序列 在[回溯算法:递增子序列](https://programmercarl.com/0491.递增子序列.html)中,处处都能看到子集的身影,但处处是陷阱,值得好好琢磨琢磨! @@ -247,9 +249,9 @@ if (startIndex >= nums.size()) { // 终止条件可以不加 **相信这个图胜过千言万语的解释了**。 -# 排列问题 +## 排列问题 -## 排列问题(一) +### 排列问题(一) [回溯算法:排列问题!](https://programmercarl.com/0046.全排列.html) 又不一样了。 @@ -266,7 +268,7 @@ if (startIndex >= nums.size()) { // 终止条件可以不加 * 每层都是从0开始搜索而不是startIndex * 需要used数组记录path里都放了哪些元素了 -## 排列问题(二) +### 排列问题(二) 排列问题也要去重了,在[回溯算法:排列问题(二)](https://programmercarl.com/0047.全排列II.html)中又一次强调了“树层去重”和“树枝去重”。 @@ -290,7 +292,7 @@ if (startIndex >= nums.size()) { // 终止条件可以不加 本题used数组即是记录path里都放了哪些元素,同时也用来去重,一举两得。 -# 去重问题 +## 去重问题 以上我都是统一使用used数组来去重的,其实使用set也可以用来去重! @@ -310,7 +312,7 @@ if (startIndex >= nums.size()) { // 终止条件可以不加 used数组可是全局变量,每层与每层之间公用一个used数组,所以空间复杂度是O(n + n),最终空间复杂度还是O(n)。 -# 重新安排行程(图论额外拓展) +## 重新安排行程(图论额外拓展) 之前说过,有递归的地方就有回溯,深度优先搜索也是用递归来实现的,所以往往伴随着回溯。 @@ -327,9 +329,9 @@ used数组可是全局变量,每层与每层之间公用一个used数组,所 本题其实是一道深度优先搜索的题目,但是我完全使用回溯法的思路来讲解这道题题目,**算是给大家拓展一下思维方式,其实深搜和回溯也是分不开的,毕竟最终都是用递归**。 -# 棋盘问题 +## 棋盘问题 -## N皇后问题 +### N皇后问题 在[回溯算法:N皇后问题](https://programmercarl.com/0051.N皇后.html)中终于迎来了传说中的N皇后。 @@ -349,7 +351,7 @@ used数组可是全局变量,每层与每层之间公用一个used数组,所 -## 解数独问题 +### 解数独问题 在[回溯算法:解数独](https://programmercarl.com/0037.解数独.html)中要征服回溯法的最后一道山峰。 @@ -373,7 +375,7 @@ used数组可是全局变量,每层与每层之间公用一个used数组,所 **这样,解数独这么难的问题也被我们攻克了**。 -# 性能分析 +## 性能分析 **关于回溯算法的复杂度分析在网上的资料鱼龙混杂,一些所谓的经典面试书籍不讲回溯算法,算法书籍对这块也避而不谈,感觉就像是算法里模糊的边界**。 @@ -410,7 +412,7 @@ N皇后问题分析: **一般说道回溯算法的复杂度,都说是指数级别的时间复杂度,这也算是一个概括吧!** -# 总结 +## 总结 **[「代码随想录」](https://img-blog.csdnimg.cn/20200815195519696.png)历时21天,14道经典题目分析,20张树形图,21篇回溯法精讲文章,从组合到切割,从子集到排列,从棋盘问题到最后的复杂度分析**,至此收尾了。 @@ -449,3 +451,4 @@ N皇后问题分析: +