From 1af721e1ed561764b081c8d8ddc25d7c614fe7fd Mon Sep 17 00:00:00 2001 From: fw_qaq <82551626+Jack-Zhang-1314@users.noreply.github.com> Date: Tue, 15 Nov 2022 21:58:16 +0800 Subject: [PATCH 01/56] =?UTF-8?q?Update=200110.=E5=B9=B3=E8=A1=A1=E4=BA=8C?= =?UTF-8?q?=E5=8F=89=E6=A0=91.md?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- problems/0110.平衡二叉树.md | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/problems/0110.平衡二叉树.md b/problems/0110.平衡二叉树.md index 6e7c8c53..9751f2dd 100644 --- a/problems/0110.平衡二叉树.md +++ b/problems/0110.平衡二叉树.md @@ -810,6 +810,38 @@ func getHeight(_ root: TreeNode?) -> Int { } ``` +### rust + +递归 + +```rust +use std::cell::RefCell; +use std::rc::Rc; +impl Solution { + pub fn is_balanced(root: Option>>) -> bool { + Self::get_depth(root) != -1 + } + pub fn get_depth(root: Option>>) -> i32 { + if root.is_none() { + return 0; + } + let right = Self::get_depth(root.as_ref().unwrap().borrow().left.clone()); + let left = Self::get_depth(root.unwrap().borrow().right.clone()); + if right == -1 { + return -1; + } + if left == -1 { + return -1; + } + if (right - left).abs() > 1 { + return -1; + } + + 1 + right.max(left) + } +} +``` +

From 9b2f1700ca45604662b4e10bd2769b5026d3b1f9 Mon Sep 17 00:00:00 2001 From: fw_qaq <82551626+Jack-Zhang-1314@users.noreply.github.com> Date: Tue, 15 Nov 2022 22:45:20 +0800 Subject: [PATCH 02/56] =?UTF-8?q?Update=200257.=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.md?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- problems/0257.二叉树的所有路径.md | 28 +++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/problems/0257.二叉树的所有路径.md b/problems/0257.二叉树的所有路径.md index 297acb60..0fb7ed0d 100644 --- a/problems/0257.二叉树的所有路径.md +++ b/problems/0257.二叉树的所有路径.md @@ -794,6 +794,34 @@ object Solution { } } ``` + +rust: + +```rust +use std::cell::RefCell; +use std::rc::Rc; +impl Solution { + pub fn binary_tree_paths(root: Option>>) -> Vec { + let mut res = vec![]; + Self::recur(&root, String::from(""), &mut res); + res + } + pub fn recur(node: &Option>>, mut path: String, res: &mut Vec) { + let r = node.as_ref().unwrap().borrow(); + path += format!("{}", r.val).as_str(); + if r.left.is_none() && r.right.is_none() { + res.push(path.to_string()); + return; + } + if r.left.is_some() { + Self::recur(&r.left, path.clone() + "->", res); + } + if r.right.is_some() { + Self::recur(&r.right, path + "->", res); + } + } +} +```

From 6e01224ee38f0f97fc1e455233948622e1dae6a0 Mon Sep 17 00:00:00 2001 From: fw_qaq <82551626+Jack-Zhang-1314@users.noreply.github.com> Date: Tue, 15 Nov 2022 22:46:07 +0800 Subject: [PATCH 03/56] =?UTF-8?q?Update=200257.=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.md?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- problems/0257.二叉树的所有路径.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/problems/0257.二叉树的所有路径.md b/problems/0257.二叉树的所有路径.md index 0fb7ed0d..80ce518a 100644 --- a/problems/0257.二叉树的所有路径.md +++ b/problems/0257.二叉树的所有路径.md @@ -798,8 +798,7 @@ object Solution { rust: ```rust -use std::cell::RefCell; -use std::rc::Rc; +// 遍历 impl Solution { pub fn binary_tree_paths(root: Option>>) -> Vec { let mut res = vec![]; From 299fab57663088a2aa12e958c36b2b04a36c0e1e Mon Sep 17 00:00:00 2001 From: fw_qaq <82551626+Jack-Zhang-1314@users.noreply.github.com> Date: Tue, 15 Nov 2022 22:56:11 +0800 Subject: [PATCH 04/56] =?UTF-8?q?Update=20problems/0257.=E4=BA=8C=E5=8F=89?= =?UTF-8?q?=E6=A0=91=E7=9A=84=E6=89=80=E6=9C=89=E8=B7=AF=E5=BE=84.md?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- problems/0257.二叉树的所有路径.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/problems/0257.二叉树的所有路径.md b/problems/0257.二叉树的所有路径.md index 80ce518a..a6e14238 100644 --- a/problems/0257.二叉树的所有路径.md +++ b/problems/0257.二叉树的所有路径.md @@ -798,7 +798,7 @@ object Solution { rust: ```rust -// 遍历 +// 递归 impl Solution { pub fn binary_tree_paths(root: Option>>) -> Vec { let mut res = vec![]; From 6772a996bba54cf0741b53a5306a51d5664ffadd Mon Sep 17 00:00:00 2001 From: wangshihua Date: Wed, 16 Nov 2022 09:27:42 +0800 Subject: [PATCH 05/56] =?UTF-8?q?feat:=E4=BF=AE=E6=94=B9=2027=20=E9=A2=98?= =?UTF-8?q?=20python=20=E4=BB=A3=E7=A0=81=E6=A0=BC=E5=BC=8F=E9=94=99?= =?UTF-8?q?=E8=AF=AF=E9=97=AE=E9=A2=98=E5=B9=B6=E5=A2=9E=E5=8A=A0=E5=BF=AB?= =?UTF-8?q?=E6=85=A2=E6=8C=87=E9=92=88=E7=9A=84=E8=A7=A3=E6=B3=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- problems/0027.移除元素.md | 38 ++++++++++++++++++++++++++--------- 1 file changed, 28 insertions(+), 10 deletions(-) diff --git a/problems/0027.移除元素.md b/problems/0027.移除元素.md index e1de7243..35d0e2c4 100644 --- a/problems/0027.移除元素.md +++ b/problems/0027.移除元素.md @@ -77,7 +77,7 @@ public: 双指针法(快慢指针法): **通过一个快指针和慢指针在一个for循环下完成两个for循环的工作。** -定义快慢指针 +定义快慢指针 * 快指针:寻找新数组的元素 ,新数组就是不含有目标元素的数组 * 慢指针:指向更新 新数组下标的位置 @@ -196,26 +196,44 @@ class Solution { Python: -```python3 +```python 3 class Solution: def removeElement(self, nums: List[int], val: int) -> int: - if nums is None or len(nums)==0: - return 0 + if nums is None or len(nums)==0: + return 0 l=0 r=len(nums)-1 - while l int: + # 快慢指针 + fast = 0 # 快指针 + slow = 0 # 慢指针 + size = len(nums) + while fast < size: # 不加等于是因为,a = size 时,nums[a] 会越界 + # slow 用来收集不等于 val 的值,如果 fast 对应值不等于 val,则把它与 slow 替换 + if nums[fast] != val: + nums[slow] = nums[fast] + slow += 1 + fast += 1 + return slow +``` + + + Go: ```go @@ -268,7 +286,7 @@ Ruby: ```ruby def remove_element(nums, val) i = 0 - nums.each_index do |j| + nums.each_index do |j| if nums[j] != val nums[i] = nums[j] i+=1 @@ -342,7 +360,7 @@ int removeElement(int* nums, int numsSize, int val){ if(nums[fast] != val) { //将其挪到慢指针指向的位置,慢指针+1 nums[slow++] = nums[fast]; - } + } } //最后慢指针的大小就是新的数组的大小 return slow; From 9969795e066996d90ae143fd974690a5e7b1af62 Mon Sep 17 00:00:00 2001 From: codeSu Date: Wed, 16 Nov 2022 21:59:33 +0800 Subject: [PATCH 06/56] =?UTF-8?q?feat:=200070.=E7=88=AC=E6=A5=BC=E6=A2=AF.?= =?UTF-8?q?md=20=E5=A2=9E=E5=8A=A0=20rust=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- problems/0070.爬楼梯.md | 31 +++++++++++++++++++++++++------ 1 file changed, 25 insertions(+), 6 deletions(-) diff --git a/problems/0070.爬楼梯.md b/problems/0070.爬楼梯.md index 335ddb23..79b2d90b 100644 --- a/problems/0070.爬楼梯.md +++ b/problems/0070.爬楼梯.md @@ -28,7 +28,7 @@ * 1 阶 + 2 阶 * 2 阶 + 1 阶 -# 视频讲解 +# 视频讲解 **《代码随想录》算法视频公开课:[带你学透动态规划-爬楼梯|LeetCode:70.爬楼梯)](https://www.bilibili.com/video/BV17h411h7UH),相信结合视频在看本篇题解,更有助于大家对本题的理解**。 @@ -216,7 +216,7 @@ public: ## 其他语言版本 -### Java +### Java ```java // 常规方式 @@ -237,7 +237,7 @@ class Solution { public int climbStairs(int n) { if(n <= 2) return n; int a = 1, b = 2, sum = 0; - + for(int i = 3; i <= n; i++){ sum = a + b; // f(i - 1) + f(i - 2) a = b; // 记录f(i - 1),即下一轮的f(i - 2) @@ -261,7 +261,7 @@ class Solution: for i in range(2,n+1): dp[i]=dp[i-1]+dp[i-2] return dp[n] - + # 空间复杂度为O(1)版本 class Solution: def climbStairs(self, n: int) -> int: @@ -275,7 +275,7 @@ class Solution: return dp[1] ``` -### Go +### Go ```Go func climbStairs(n int) int { if n==1{ @@ -303,7 +303,7 @@ var climbStairs = function(n) { }; ``` -TypeScript +### TypeScript > 爬2阶 @@ -447,7 +447,26 @@ public class Solution { } ``` +### Rust +```rust +impl Solution { + pub fn climb_stairs(n: i32) -> i32 { + if n <= 2 { + return n; + } + let mut a = 1; + let mut b = 2; + let mut f = 0; + for i in 2..n { + f = a + b; + a = b; + b = f; + } + return f; + } +} +```

From dfe98e3766ed8b2a84a718d09c5bef1c415379ac Mon Sep 17 00:00:00 2001 From: syuxin2019 <519802856@qq.com> Date: Fri, 18 Nov 2022 19:12:21 +0800 Subject: [PATCH 07/56] modified 707.md --- problems/0707.设计链表.md | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/problems/0707.设计链表.md b/problems/0707.设计链表.md index 1264983b..5393c038 100644 --- a/problems/0707.设计链表.md +++ b/problems/0707.设计链表.md @@ -106,11 +106,10 @@ public: // 在第index个节点之前插入一个新节点,例如index为0,那么新插入的节点为链表的新头节点。 // 如果index 等于链表的长度,则说明是新插入的节点为链表的尾结点 // 如果index大于链表的长度,则返回空 - // 如果index小于0,则置为0,作为链表的新头节点。 + // 如果index小于0,则在头部插入节点 void addAtIndex(int index, int val) { - if (index > _size || index < 0) { - return; - } + if(index > _size) return; + if(index < 0) index = 0; LinkedNode* newNode = new LinkedNode(val); LinkedNode* cur = _dummyHead; while(index--) { From 944ce27a28b6582e71f3626c39708e84ec4a0c34 Mon Sep 17 00:00:00 2001 From: fw_qaq <82551626+Jack-Zhang-1314@users.noreply.github.com> Date: Sat, 19 Nov 2022 00:07:04 +0800 Subject: [PATCH 08/56] =?UTF-8?q?Update=20=E4=BA=8C=E5=8F=89=E6=A0=91?= =?UTF-8?q?=E4=B8=AD=E9=80=92=E5=BD=92=E5=B8=A6=E7=9D=80=E5=9B=9E=E6=BA=AF?= =?UTF-8?q?.md?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- problems/二叉树中递归带着回溯.md | 32 ++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/problems/二叉树中递归带着回溯.md b/problems/二叉树中递归带着回溯.md index e35a5214..dc576c60 100644 --- a/problems/二叉树中递归带着回溯.md +++ b/problems/二叉树中递归带着回溯.md @@ -617,6 +617,38 @@ func _binaryTreePaths3(_ root: TreeNode, res: inout [String], paths: inout [Int] } ``` +### Rust + +> 100.相同的树 + +```rsut +use std::cell::RefCell; +use std::rc::Rc; +impl Solution { + pub fn is_same_tree( + p: Option>>, + q: Option>>, + ) -> bool { + match (p, q) { + (None, None) => true, + (None, Some(_)) => false, + (Some(_), None) => false, + (Some(n1), Some(n2)) => { + if n1.borrow().val == n2.borrow().val { + let right = + Self::is_same_tree(n1.borrow().left.clone(), n2.borrow().left.clone()); + let left = + Self::is_same_tree(n1.borrow().right.clone(), n2.borrow().right.clone()); + right && left + } else { + false + } + } + } + } +} +``` +

From 4bae1e84baffb99c60f073eeca515c9c4a14697b Mon Sep 17 00:00:00 2001 From: fw_qaq <82551626+Jack-Zhang-1314@users.noreply.github.com> Date: Sat, 19 Nov 2022 01:39:14 +0800 Subject: [PATCH 09/56] =?UTF-8?q?Update=20=E4=BA=8C=E5=8F=89=E6=A0=91?= =?UTF-8?q?=E4=B8=AD=E9=80=92=E5=BD=92=E5=B8=A6=E7=9D=80=E5=9B=9E=E6=BA=AF?= =?UTF-8?q?.md?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- problems/二叉树中递归带着回溯.md | 37 ++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/problems/二叉树中递归带着回溯.md b/problems/二叉树中递归带着回溯.md index dc576c60..9bf7405d 100644 --- a/problems/二叉树中递归带着回溯.md +++ b/problems/二叉树中递归带着回溯.md @@ -649,6 +649,43 @@ impl Solution { } ``` +> 257.二叉树的不同路径 + +```rust +// 递归 +use std::cell::RefCell; +use std::rc::Rc; +impl Solution { + pub fn binary_tree_paths(root: Option>>) -> Vec { + let mut res = vec![]; + let mut path = vec![]; + Self::recur(&root, &mut path, &mut res); + res + } + + pub fn recur( + root: &Option>>, + path: &mut Vec, + res: &mut Vec, + ) { + let node = root.as_ref().unwrap().borrow(); + path.push(node.val.to_string()); + if node.left.is_none() && node.right.is_none() { + res.push(path.join("->")); + return; + } + if node.left.is_some() { + Self::recur(&node.left, path, res); + path.pop(); //回溯 + } + if node.right.is_some() { + Self::recur(&node.right, path, res); + path.pop(); //回溯 + } + } +} +``` +

From 65857d15333bfe5ecf9a7f56fb0abb8a4c30ebe2 Mon Sep 17 00:00:00 2001 From: Zeeland <287017217@qq.com> Date: Sat, 19 Nov 2022 09:50:57 +0800 Subject: [PATCH 10/56] =?UTF-8?q?update=200695.=E5=B2=9B=E5=B1=BF=E7=9A=84?= =?UTF-8?q?=E6=9C=80=E5=A4=A7=E9=9D=A2=E7=A7=AF.md?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- problems/0695.岛屿的最大面积.md | 1 - 1 file changed, 1 deletion(-) diff --git a/problems/0695.岛屿的最大面积.md b/problems/0695.岛屿的最大面积.md index 414efe0b..76740ef1 100644 --- a/problems/0695.岛屿的最大面积.md +++ b/problems/0695.岛屿的最大面积.md @@ -197,7 +197,6 @@ class Solution: if not visited[i][j] and grid[i][j] == 1: # 每一个新岛屿 self.count = 0 - print(f'{self.count}') self.bfs(grid, visited, i, j) result = max(result, self.count) From 98ade76980dfc8ace03d0c61f2491ed3b39f800a Mon Sep 17 00:00:00 2001 From: Allen <2439506288@qq.com> Date: Sun, 20 Nov 2022 08:20:52 +0800 Subject: [PATCH 11/56] =?UTF-8?q?update=200052.N=E7=9A=87=E5=90=8E2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- problems/0052.N皇后II.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/problems/0052.N皇后II.md b/problems/0052.N皇后II.md index e4faac0c..1c88fb3c 100644 --- a/problems/0052.N皇后II.md +++ b/problems/0052.N皇后II.md @@ -8,7 +8,7 @@ # 52. N皇后II -题目链接:https://leetcode.cn/problems/n-queens-ii/ +题目链接:[https://leetcode.cn/problems/n-queens-ii/](https://leetcode.cn/problems/n-queens-ii/) n 皇后问题研究的是如何将 n 个皇后放置在 n×n 的棋盘上,并且使皇后彼此之间不能相互攻击。 @@ -308,3 +308,4 @@ class Solution { + From 15379361aa9b1c1c062870d9e4790ca24ae51a1b Mon Sep 17 00:00:00 2001 From: fw_qaq <82551626+Jack-Zhang-1314@users.noreply.github.com> Date: Sun, 20 Nov 2022 16:11:25 +0800 Subject: [PATCH 12/56] =?UTF-8?q?Update=200404.=E5=B7=A6=E5=8F=B6=E5=AD=90?= =?UTF-8?q?=E4=B9=8B=E5=92=8C.md?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- problems/0404.左叶子之和.md | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/problems/0404.左叶子之和.md b/problems/0404.左叶子之和.md index 6b6fe729..3118b7c0 100644 --- a/problems/0404.左叶子之和.md +++ b/problems/0404.左叶子之和.md @@ -575,6 +575,31 @@ object Solution { } ``` +### Rust + +**递归** + +```rust +use std::cell::RefCell; +use std::rc::Rc; +impl Solution { + pub fn sum_of_left_leaves(root: Option>>) -> i32 { + let mut res = 0; + if let Some(node) = root { + if let Some(left) = &node.borrow().left { + if left.borrow().right.is_none() && left.borrow().right.is_none() { + res += left.borrow().val; + } + } + res + Self::sum_of_left_leaves(node.borrow().left.clone()) + + Self::sum_of_left_leaves(node.borrow().right.clone()) + } else { + 0 + } + } +} +``` +

From 59d17ea08d37ab5e85cae19c472686fa0a4d4a69 Mon Sep 17 00:00:00 2001 From: fw_qaq <82551626+Jack-Zhang-1314@users.noreply.github.com> Date: Sun, 20 Nov 2022 16:39:42 +0800 Subject: [PATCH 13/56] =?UTF-8?q?Update=200404.=E5=B7=A6=E5=8F=B6=E5=AD=90?= =?UTF-8?q?=E4=B9=8B=E5=92=8C.md?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- problems/0404.左叶子之和.md | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/problems/0404.左叶子之和.md b/problems/0404.左叶子之和.md index 3118b7c0..f5b9ca39 100644 --- a/problems/0404.左叶子之和.md +++ b/problems/0404.左叶子之和.md @@ -600,6 +600,33 @@ impl Solution { } ``` +**迭代:** + +```rust +use std::cell::RefCell; +use std::rc::Rc; +impl Solution { + pub fn sum_of_left_leaves(root: Option>>) -> i32 { + let mut res = 0; + let mut stack = vec![root]; + while !stack.is_empty() { + if let Some(node) = stack.pop().unwrap() { + if let Some(left) = &node.borrow().left { + if left.borrow().left.is_none() && left.borrow().right.is_none() { + res += left.borrow().val; + } + stack.push(Some(left.to_owned())); + } + if let Some(right) = &node.borrow().right { + stack.push(Some(right.to_owned())); + } + } + } + res + } +} +``` +

From 145114872d6d43e6f3e938891249bf52c7aea8c2 Mon Sep 17 00:00:00 2001 From: fw_qaq <82551626+Jack-Zhang-1314@users.noreply.github.com> Date: Sun, 20 Nov 2022 16:58:25 +0800 Subject: [PATCH 14/56] =?UTF-8?q?Update=200513.=E6=89=BE=E6=A0=91=E5=B7=A6?= =?UTF-8?q?=E4=B8=8B=E8=A7=92=E7=9A=84=E5=80=BC.md?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- problems/0513.找树左下角的值.md | 34 ++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/problems/0513.找树左下角的值.md b/problems/0513.找树左下角的值.md index fd6e5d95..cfb4a6c4 100644 --- a/problems/0513.找树左下角的值.md +++ b/problems/0513.找树左下角的值.md @@ -587,6 +587,40 @@ object Solution { } ``` +### rust + +**层序遍历** + +```rust +use std::cell::RefCell; +use std::collections::VecDeque; +use std::rc::Rc; +impl Solution { + pub fn find_bottom_left_value(root: Option>>) -> i32 { + let mut queue = VecDeque::new(); + let mut res = 0; + if root.is_some() { + queue.push_back(root); + } + while !queue.is_empty() { + for i in 0..queue.len() { + let node = queue.pop_front().unwrap().unwrap(); + if i == 1 { + res = node.borrow().val; + } + if node.borrow().left.is_some() { + queue.push_back(node.borrow().left.clone()); + } + if node.borrow().right.is_some() { + queue.push_back(node.borrow().right.clone()); + } + } + } + res + } +} +``` +

From 25e055ec7343a7ff79303062fbbf32ec22b9e02e Mon Sep 17 00:00:00 2001 From: fw_qaq <82551626+Jack-Zhang-1314@users.noreply.github.com> Date: Sun, 20 Nov 2022 16:59:01 +0800 Subject: [PATCH 15/56] =?UTF-8?q?Update=200513.=E6=89=BE=E6=A0=91=E5=B7=A6?= =?UTF-8?q?=E4=B8=8B=E8=A7=92=E7=9A=84=E5=80=BC.md?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- problems/0513.找树左下角的值.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/problems/0513.找树左下角的值.md b/problems/0513.找树左下角的值.md index cfb4a6c4..70be7051 100644 --- a/problems/0513.找树左下角的值.md +++ b/problems/0513.找树左下角的值.md @@ -605,7 +605,7 @@ impl Solution { while !queue.is_empty() { for i in 0..queue.len() { let node = queue.pop_front().unwrap().unwrap(); - if i == 1 { + if i == 0 { res = node.borrow().val; } if node.borrow().left.is_some() { From 032527d25ad573ab3e7c3c715d2f6d3d66f0968f Mon Sep 17 00:00:00 2001 From: fw_qaq <82551626+Jack-Zhang-1314@users.noreply.github.com> Date: Sun, 20 Nov 2022 17:43:25 +0800 Subject: [PATCH 16/56] =?UTF-8?q?Update=200513.=E6=89=BE=E6=A0=91=E5=B7=A6?= =?UTF-8?q?=E4=B8=8B=E8=A7=92=E7=9A=84=E5=80=BC.md?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- problems/0513.找树左下角的值.md | 37 ++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/problems/0513.找树左下角的值.md b/problems/0513.找树左下角的值.md index 70be7051..622a11b5 100644 --- a/problems/0513.找树左下角的值.md +++ b/problems/0513.找树左下角的值.md @@ -621,6 +621,43 @@ impl Solution { } ``` +**递归** + +```rust +use std::cell::RefCell; +use std::rc::Rc; +impl Solution { + //*递归*/ + pub fn find_bottom_left_value(root: Option>>) -> i32 { + let mut res = 0; + let mut max_depth = i32::MIN; + Self::traversal(root, 0, &mut max_depth, &mut res); + res + } + fn traversal( + root: Option>>, + depth: i32, + max_depth: &mut i32, + res: &mut i32, + ) { + let node = root.unwrap(); + if node.borrow().left.is_none() && node.borrow().right.is_none() { + if depth > *max_depth { + *max_depth = depth; + *res = node.borrow().val; + } + return; + } + if node.borrow().left.is_some() { + Self::traversal(node.borrow().left.clone(), depth + 1, max_depth, res); + } + if node.borrow().right.is_some() { + Self::traversal(node.borrow().right.clone(), depth + 1, max_depth, res); + } + } +} +``` +

From d3e35b3ae961d14dbcb23a9658d3163ca50dd284 Mon Sep 17 00:00:00 2001 From: fw_qaq <82551626+Jack-Zhang-1314@users.noreply.github.com> Date: Sun, 20 Nov 2022 18:02:32 +0800 Subject: [PATCH 17/56] =?UTF-8?q?Update=200112.=E8=B7=AF=E5=BE=84=E6=80=BB?= =?UTF-8?q?=E5=92=8C.md?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- problems/0112.路径总和.md | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/problems/0112.路径总和.md b/problems/0112.路径总和.md index d50f23f9..482787bf 100644 --- a/problems/0112.路径总和.md +++ b/problems/0112.路径总和.md @@ -1213,6 +1213,28 @@ object Solution { } ``` +## rust + +### 112.路径总和.md + +```rust +use std::rc::Rc; +use std::cell::RefCell; +impl Solution { + pub fn has_path_sum(root: Option>>, target_sum: i32) -> bool { + if root.is_none() { + return false; + } + let node = root.unwrap(); + if node.borrow().left.is_none() && node.borrow().right.is_none() { + return node.borrow().val == target_sum; + } + return Self::has_path_sum(node.borrow().left.clone(), target_sum - node.borrow().val) + || Self::has_path_sum(node.borrow().right.clone(), target_sum - node.borrow().val); + } +} +``` +

From 47b7cf3cae785ec43be3e08dc8db8143d3f9aaca Mon Sep 17 00:00:00 2001 From: fw_qaq <82551626+Jack-Zhang-1314@users.noreply.github.com> Date: Sun, 20 Nov 2022 22:06:39 +0800 Subject: [PATCH 18/56] =?UTF-8?q?Update=200112.=E8=B7=AF=E5=BE=84=E6=80=BB?= =?UTF-8?q?=E5=92=8C.md?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- problems/0112.路径总和.md | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/problems/0112.路径总和.md b/problems/0112.路径总和.md index 482787bf..f717f6b8 100644 --- a/problems/0112.路径总和.md +++ b/problems/0112.路径总和.md @@ -1217,6 +1217,8 @@ object Solution { ### 112.路径总和.md +递归: + ```rust use std::rc::Rc; use std::cell::RefCell; @@ -1235,6 +1237,38 @@ impl Solution { } ``` +迭代: + +```rust +use std::rc::Rc; +use std::cell::RefCell; +impl Solution { + pub fn has_path_sum(root: Option>>, target_sum: i32) -> bool { + let mut stack = vec![]; + if let Some(node) = root { + stack.push((node.borrow().val, node.to_owned())); + } + while !stack.is_empty() { + let (value, node) = stack.pop().unwrap(); + if node.borrow().left.is_none() && node.borrow().right.is_none() && value == target_sum + { + return true; + } + if node.borrow().left.is_some() { + if let Some(r) = node.borrow().left.as_ref() { + stack.push((r.borrow().val + value, r.to_owned())); + } + } + if node.borrow().right.is_some() { + if let Some(r) = node.borrow().right.as_ref() { + stack.push((r.borrow().val + value, r.to_owned())); + } + } + } + false + } +``` +

From d791cc76b6779799779c33f77fc4c6e59d7a6fee Mon Sep 17 00:00:00 2001 From: wang2jun <91008685+wang2jun@users.noreply.github.com> Date: Mon, 21 Nov 2022 13:27:00 +0800 Subject: [PATCH 19/56] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=20657.=20=E6=9C=BA?= =?UTF-8?q?=E5=99=A8=E4=BA=BA=E8=83=BD=E5=90=A6=E8=BF=94=E5=9B=9E=E5=8E=9F?= =?UTF-8?q?=E7=82=B9=20TypeScript=20=E7=89=88=E6=9C=AC=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 增加 657. 机器人能否返回原点 TypeScript 版本代码 --- problems/0657.机器人能否返回原点.md | 31 ++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/problems/0657.机器人能否返回原点.md b/problems/0657.机器人能否返回原点.md index 017c5ecc..ab4bf152 100644 --- a/problems/0657.机器人能否返回原点.md +++ b/problems/0657.机器人能否返回原点.md @@ -150,6 +150,37 @@ var judgeCircle = function(moves) { ``` +## TypeScript + +```ts +var judgeCircle = function (moves) { + let x = 0 + let y = 0 + for (let i = 0; i < moves.length; i++) { + switch (moves[i]) { + case 'L': { + x-- + break + } + case 'R': { + x++ + break + } + case 'U': { + y-- + break + } + case 'D': { + y++ + break + } + } + } + return x === 0 && y === 0 +}; +``` + +

From 1fef4a77be4ceefde5406a774706c00de77917cc Mon Sep 17 00:00:00 2001 From: fw_qaq <82551626+Jack-Zhang-1314@users.noreply.github.com> Date: Mon, 21 Nov 2022 22:31:55 +0800 Subject: [PATCH 20/56] =?UTF-8?q?Update=200112.=E8=B7=AF=E5=BE=84=E6=80=BB?= =?UTF-8?q?=E5=92=8C.md?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- problems/0112.路径总和.md | 49 +++++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) diff --git a/problems/0112.路径总和.md b/problems/0112.路径总和.md index f717f6b8..effe7649 100644 --- a/problems/0112.路径总和.md +++ b/problems/0112.路径总和.md @@ -1269,6 +1269,55 @@ impl Solution { } ``` +### 113.路径总和-ii + +```rust +impl Solution { + pub fn path_sum(root: Option>>, target_sum: i32) -> Vec> { + let mut res = vec![]; + let mut route = vec![]; + if root.is_none() { + return res; + } else { + route.push(root.as_ref().unwrap().borrow().val); + } + Self::recur( + &root, + target_sum - root.as_ref().unwrap().borrow().val, + &mut res, + &mut route, + ); + res + } + + pub fn recur( + root: &Option>>, + sum: i32, + res: &mut Vec>, + route: &mut Vec, + ) { + let node = root.as_ref().unwrap().borrow(); + if node.left.is_none() && node.right.is_none() && sum == 0 { + res.push(route.to_vec()); + return; + } + if node.left.is_some() { + let left = node.left.as_ref().unwrap(); + route.push(left.borrow().val); + Self::recur(&node.left, sum - left.borrow().val, res, route); + route.pop(); + } + if node.right.is_some() { + let right = node.right.as_ref().unwrap(); + route.push(right.borrow().val); + Self::recur(&node.right, sum - right.borrow().val, res, route); + route.pop(); + } + } +} + +``` +

From 3b3ed756664435b73fceb20a971fa8ef03d608f8 Mon Sep 17 00:00:00 2001 From: fw_qaq <82551626+Jack-Zhang-1314@users.noreply.github.com> Date: Sat, 26 Nov 2022 15:16:06 +0800 Subject: [PATCH 21/56] =?UTF-8?q?Update=200617.=E5=90=88=E5=B9=B6=E4=BA=8C?= =?UTF-8?q?=E5=8F=89=E6=A0=91.md?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- problems/0617.合并二叉树.md | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/problems/0617.合并二叉树.md b/problems/0617.合并二叉树.md index db2d3762..f0ecf79b 100644 --- a/problems/0617.合并二叉树.md +++ b/problems/0617.合并二叉树.md @@ -691,6 +691,35 @@ object Solution { } ``` +### rust + +递归: + +```rust +use std::cell::RefCell; +use std::rc::Rc; +impl Solution { + pub fn merge_trees( + root1: Option>>, + root2: Option>>, + ) -> Option>> { + if root1.is_none() { + return root2; + } + if root2.is_none() { + return root1; + } + let binding = root1.clone(); + let mut node1 = binding.as_ref().unwrap().borrow_mut(); + let node2 = root2.as_ref().unwrap().borrow_mut(); + node1.left = Self::merge_trees(node1.left.clone(), node2.left.clone()); + node1.right = Self::merge_trees(node1.right.clone(), node2.right.clone()); + node1.val += node2.val; + + root1 + } +} +```

From ae99d647ac6f662a9a97340511c07e541c2f257a Mon Sep 17 00:00:00 2001 From: fw_qaq <82551626+Jack-Zhang-1314@users.noreply.github.com> Date: Sat, 26 Nov 2022 16:41:16 +0800 Subject: [PATCH 22/56] =?UTF-8?q?Update=200617.=E5=90=88=E5=B9=B6=E4=BA=8C?= =?UTF-8?q?=E5=8F=89=E6=A0=91.md?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- problems/0617.合并二叉树.md | 43 ++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/problems/0617.合并二叉树.md b/problems/0617.合并二叉树.md index f0ecf79b..9fe457c6 100644 --- a/problems/0617.合并二叉树.md +++ b/problems/0617.合并二叉树.md @@ -721,6 +721,49 @@ impl Solution { } ``` +迭代: + +```rust +impl Solution { + pub fn merge_trees( + root1: Option>>, + root2: Option>>, + ) -> Option>> { + if root1.is_none() { + return root2; + } + if root2.is_none() { + return root1; + } + let mut stack = vec![]; + stack.push(root2); + stack.push(root1.clone()); + while !stack.is_empty() { + let node1 = stack.pop().unwrap().unwrap(); + let node2 = stack.pop().unwrap().unwrap(); + let mut node1 = node1.borrow_mut(); + let node2 = node2.borrow(); + node1.val += node2.val; + if node1.left.is_some() && node2.left.is_some() { + stack.push(node2.left.clone()); + stack.push(node1.left.clone()); + } + if node1.right.is_some() && node2.right.is_some() { + stack.push(node2.right.clone()); + stack.push(node1.right.clone()); + } + if node1.left.is_none() && node2.left.is_some() { + node1.left = node2.left.clone(); + } + if node1.right.is_none() && node2.right.is_some() { + node1.right = node2.right.clone(); + } + } + root1 + } +} +``` +

From 5c4b8b3d8140ecc67f917f49899d77ee49f9b83d Mon Sep 17 00:00:00 2001 From: fw_qaq <82551626+Jack-Zhang-1314@users.noreply.github.com> Date: Sat, 26 Nov 2022 18:07:46 +0800 Subject: [PATCH 23/56] =?UTF-8?q?Update=200700.=E4=BA=8C=E5=8F=89=E6=90=9C?= =?UTF-8?q?=E7=B4=A2=E6=A0=91=E4=B8=AD=E7=9A=84=E6=90=9C=E7=B4=A2.md?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- problems/0700.二叉搜索树中的搜索.md | 27 ++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/problems/0700.二叉搜索树中的搜索.md b/problems/0700.二叉搜索树中的搜索.md index 2ee2bdb0..a0143bd8 100644 --- a/problems/0700.二叉搜索树中的搜索.md +++ b/problems/0700.二叉搜索树中的搜索.md @@ -414,6 +414,33 @@ object Solution { } ``` +### rust + +递归: + +```rust +use std::cell::RefCell; +use std::rc::Rc; +impl Solution { + pub fn search_bst( + root: Option>>, + val: i32, + ) -> Option>> { + if root.is_none() || root.as_ref().unwrap().borrow().val == val { + return root; + } + let node_val = root.as_ref().unwrap().borrow().val; + if node_val > val { + return Self::search_bst(root.as_ref().unwrap().borrow().left.clone(), val); + } + if node_val < val { + return Self::search_bst(root.unwrap().borrow().right.clone(), val); + } + None + } +} +``` +

From 4be111b3d170b7f3ff5888d0cb343368818e4fd2 Mon Sep 17 00:00:00 2001 From: fw_qaq <82551626+Jack-Zhang-1314@users.noreply.github.com> Date: Sat, 26 Nov 2022 18:25:55 +0800 Subject: [PATCH 24/56] =?UTF-8?q?Update=200700.=E4=BA=8C=E5=8F=89=E6=90=9C?= =?UTF-8?q?=E7=B4=A2=E6=A0=91=E4=B8=AD=E7=9A=84=E6=90=9C=E7=B4=A2.md?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- problems/0700.二叉搜索树中的搜索.md | 23 ++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/problems/0700.二叉搜索树中的搜索.md b/problems/0700.二叉搜索树中的搜索.md index a0143bd8..c09f11b9 100644 --- a/problems/0700.二叉搜索树中的搜索.md +++ b/problems/0700.二叉搜索树中的搜索.md @@ -441,6 +441,29 @@ impl Solution { } ``` +迭代: + +```rust +use std::cell::RefCell; +use std::rc::Rc; +use std::cmp; +impl Solution { + pub fn search_bst( + mut root: Option>>, + val: i32, + ) -> Option>> { + while let Some(ref node) = root.clone() { + match val.cmp(&node.borrow().val) { + cmp::Ordering::Less => root = node.borrow().left.clone(), + cmp::Ordering::Equal => return root, + cmp::Ordering::Greater => root = node.borrow().right.clone(), + }; + } + None + } +} +``` +

From dc3517c1b089933ed21f69b807bcc00aba887baa Mon Sep 17 00:00:00 2001 From: Yuhao Ju Date: Wed, 30 Nov 2022 15:36:25 +0800 Subject: [PATCH 25/56] =?UTF-8?q?update=200104.=E4=BA=8C=E5=8F=89=E6=A0=91?= =?UTF-8?q?=E7=9A=84=E6=9C=80=E5=A4=A7=E6=B7=B1=E5=BA=A6:=20=E8=B0=83?= =?UTF-8?q?=E6=95=B4=E4=B8=80=E6=AE=B5=20js=20=E4=BB=A3=E7=A0=81=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/0104.二叉树的最大深度.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/problems/0104.二叉树的最大深度.md b/problems/0104.二叉树的最大深度.md index ee7bd50e..03322c9a 100644 --- a/problems/0104.二叉树的最大深度.md +++ b/problems/0104.二叉树的最大深度.md @@ -59,7 +59,7 @@ int getdepth(treenode* node) if (node == NULL) return 0; ``` -3. 确定单层递归的逻辑:先求它的左子树的深度,再求的右子树的深度,最后取左右深度最大的数值 再+1 (加1是因为算上当前中间节点)就是目前节点为根节点的树的深度。 +3. 确定单层递归的逻辑:先求它的左子树的深度,再求右子树的深度,最后取左右深度最大的数值 再+1 (加1是因为算上当前中间节点)就是目前节点为根节点的树的深度。 代码如下: @@ -591,15 +591,15 @@ var maxdepth = function(root) { var maxdepth = function(root) { //使用递归的方法 递归三部曲 //1. 确定递归函数的参数和返回值 - const getdepth=function(node){ + const getdepth = function(node) { //2. 确定终止条件 - if(node===null){ + if(node === null) { return 0; } //3. 确定单层逻辑 - let leftdepth=getdepth(node.left); - let rightdepth=getdepth(node.right); - let depth=1+Math.max(leftdepth,rightdepth); + let leftdepth = getdepth(node.left); + let rightdepth = getdepth(node.right); + let depth = 1 + Math.max(leftdepth, rightdepth); return depth; } return getdepth(root); From 1d857164728f7846abdc716e731c8518a10d6925 Mon Sep 17 00:00:00 2001 From: Yuhao Ju Date: Wed, 30 Nov 2022 15:45:57 +0800 Subject: [PATCH 26/56] =?UTF-8?q?update=200111.=E4=BA=8C=E5=8F=89=E6=A0=91?= =?UTF-8?q?=E7=9A=84=E6=9C=80=E5=B0=8F=E6=B7=B1=E5=BA=A6=EF=BC=9A=E4=BF=AE?= =?UTF-8?q?=E6=94=B9=E6=96=87=E6=9C=AC=E9=94=99=E5=AD=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- problems/0111.二叉树的最小深度.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/problems/0111.二叉树的最小深度.md b/problems/0111.二叉树的最小深度.md index 0b2ec0f6..cbe7b7ec 100644 --- a/problems/0111.二叉树的最小深度.md +++ b/problems/0111.二叉树的最小深度.md @@ -39,7 +39,7 @@ * 二叉树节点的深度:指从根节点到该节点的最长简单路径边的条数或者节点数(取决于深度从0开始还是从1开始) * 二叉树节点的高度:指从该节点到叶子节点的最长简单路径边的条数后者节点数(取决于高度从0开始还是从1开始) -那么使用后序遍历,其实求的是根节点到叶子节点的最小距离,就是求高度的过程,这不过这个最小距离 也同样是最小深度。 +那么使用后序遍历,其实求的是根节点到叶子节点的最小距离,就是求高度的过程,不过这个最小距离 也同样是最小深度。 以下讲解中遍历顺序上依然采用后序遍历(因为要比较递归返回之后的结果,本文我也给出前序遍历的写法)。 @@ -199,7 +199,7 @@ public: 如果对层序遍历还不清楚的话,可以看这篇:[二叉树:层序遍历登场!](https://programmercarl.com/0102.二叉树的层序遍历.html) -**需要注意的是,只有当左右孩子都为空的时候,才说明遍历的最低点了。如果其中一个孩子为空则不是最低点** +**需要注意的是,只有当左右孩子都为空的时候,才说明遍历到最低点了。如果其中一个孩子不为空则不是最低点** 代码如下:(详细注释) From ae13f9570900246a61b18e0901e7f955812afc62 Mon Sep 17 00:00:00 2001 From: Yuhao Ju Date: Wed, 30 Nov 2022 16:54:15 +0800 Subject: [PATCH 27/56] =?UTF-8?q?update=200222.=E5=AE=8C=E5=85=A8=E4=BA=8C?= =?UTF-8?q?=E5=8F=89=E6=A0=91=E7=9A=84=E8=8A=82=E7=82=B9=E4=B8=AA=E6=95=B0?= =?UTF-8?q?:=20=E6=9B=BF=E6=8D=A2=20java=20=E4=BB=A3=E7=A0=81=EF=BC=8C?= =?UTF-8?q?=E8=B0=83=E6=95=B4=20js=20=E6=A0=BC=E5=BC=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../0222.完全二叉树的节点个数.md | 90 +++++++++---------- 1 file changed, 43 insertions(+), 47 deletions(-) diff --git a/problems/0222.完全二叉树的节点个数.md b/problems/0222.完全二叉树的节点个数.md index 6754864d..7e763bc6 100644 --- a/problems/0222.完全二叉树的节点个数.md +++ b/problems/0222.完全二叉树的节点个数.md @@ -63,7 +63,7 @@ int getNodesNum(TreeNode* cur) { if (cur == NULL) return 0; ``` -3. 确定单层递归的逻辑:先求它的左子树的节点数量,再求的右子树的节点数量,最后取总和再加一 (加1是因为算上当前中间节点)就是目前节点为根节点的节点数量。 +3. 确定单层递归的逻辑:先求它的左子树的节点数量,再求右子树的节点数量,最后取总和再加一 (加1是因为算上当前中间节点)就是目前节点为根节点的节点数量。 代码如下: @@ -168,7 +168,7 @@ public: 可以看出如果整个树不是满二叉树,就递归其左右孩子,直到遇到满二叉树为止,用公式计算这个子树(满二叉树)的节点数量。 -这里关键在于如果去判断一个左子树或者右子树是不是满二叉树呢? +这里关键在于如何去判断一个左子树或者右子树是不是满二叉树呢? 在完全二叉树中,如果递归向左遍历的深度等于递归向右遍历的深度,那说明就是满二叉树。如图: @@ -178,13 +178,13 @@ public: ![](https://code-thinking-1253855093.file.myqcloud.com/pics/20220829163709.png) -哪有录友说了,这种情况,递归向左遍历的深度等于递归向右遍历的深度,但也不是满二叉树,如题: +那有录友说了,这种情况,递归向左遍历的深度等于递归向右遍历的深度,但也不是满二叉树,如题: ![](https://code-thinking-1253855093.file.myqcloud.com/pics/20220829163811.png) 如果这么想,大家就是对 完全二叉树理解有误区了,**以上这棵二叉树,它根本就不是一个完全二叉树**! -判断其子树岂不是满二叉树,如果是则利用用公式计算这个子树(满二叉树)的节点数量,如果不是则继续递归,那么 在递归三部曲中,第二部:终止条件的写法应该是这样的: +判断其子树是不是满二叉树,如果是则利用公式计算这个子树(满二叉树)的节点数量,如果不是则继续递归,那么 在递归三部曲中,第二部:终止条件的写法应该是这样的: ```CPP if (root == nullptr) return 0; @@ -292,26 +292,22 @@ class Solution { * 满二叉树的结点数为:2^depth - 1 */ public int countNodes(TreeNode root) { - if(root == null) { - return 0; + if (root == null) return 0; + TreeNode left = root.left; + TreeNode right = root.right; + int leftDepth = 0, rightDepth = 0; // 这里初始为0是有目的的,为了下面求指数方便 + while (left != null) { // 求左子树深度 + left = left.left; + leftDepth++; } - int leftDepth = getDepth(root.left); - int rightDepth = getDepth(root.right); - if (leftDepth == rightDepth) {// 左子树是满二叉树 - // 2^leftDepth其实是 (2^leftDepth - 1) + 1 ,左子树 + 根结点 - return (1 << leftDepth) + countNodes(root.right); - } else {// 右子树是满二叉树 - return (1 << rightDepth) + countNodes(root.left); + while (right != null) { // 求右子树深度 + right = right.right; + rightDepth++; } - } - - private int getDepth(TreeNode root) { - int depth = 0; - while (root != null) { - root = root.left; - depth++; + if (leftDepth == rightDepth) { + return (2 << leftDepth) - 1; // 注意(2<<1) 相当于2^2,所以leftDepth初始为0 } - return depth; + return countNodes(root.left) + countNodes(root.right) + 1; } } ``` @@ -397,7 +393,7 @@ class Solution: * Right *TreeNode * } */ -//本题直接就是求有多少个节点,无脑存进数组算长度就行了。 +//本题直接就是求有多少个节点,无脑存进结果变量就行了。 func countNodes(root *TreeNode) int { if root == nil { return 0 @@ -473,15 +469,15 @@ func countNodes(root *TreeNode) int { var countNodes = function(root) { //递归法计算二叉树节点数 // 1. 确定递归函数参数 - const getNodeSum=function(node){ + const getNodeSum = function(node) { //2. 确定终止条件 - if(node===null){ + if(node === null) { return 0; } //3. 确定单层递归逻辑 - let leftNum=getNodeSum(node.left); - let rightNum=getNodeSum(node.right); - return leftNum+rightNum+1; + let leftNum = getNodeSum(node.left); + let rightNum = getNodeSum(node.right); + return leftNum + rightNum + 1; } return getNodeSum(root); }; @@ -491,19 +487,19 @@ var countNodes = function(root) { ```javascript var countNodes = function(root) { //层序遍历 - let queue=[]; - if(root===null){ + let queue = []; + if(root === null) { return 0; } queue.push(root); - let nodeNums=0; - while(queue.length){ - let length=queue.length; - while(length--){ - let node=queue.shift(); + let nodeNums = 0; + while(queue.length) { + let length = queue.length; + while(length--) { + let node = queue.shift(); nodeNums++; - node.left&&queue.push(node.left); - node.right&&queue.push(node.right); + node.left && queue.push(node.left); + node.right && queue.push(node.right); } } return nodeNums; @@ -514,24 +510,24 @@ var countNodes = function(root) { ```javascript var countNodes = function(root) { //利用完全二叉树的特点 - if(root===null){ + if(root === null) { return 0; } - let left=root.left; - let right=root.right; - let leftDepth=0,rightDepth=0; - while(left){ - left=left.left; + let left = root.left; + let right = root.right; + let leftDepth = 0, rightDepth = 0; + while(left) { + left = left.left; leftDepth++; } - while(right){ - right=right.right; + while(right) { + right = right.right; rightDepth++; } - if(leftDepth==rightDepth){ - return Math.pow(2,leftDepth+1)-1; + if(leftDepth == rightDepth) { + return Math.pow(2, leftDepth+1) - 1; } - return countNodes(root.left)+countNodes(root.right)+1; + return countNodes(root.left) + countNodes(root.right) + 1; }; ``` From 0b60defcb7afebd129c9bf79504fc1b3608bfd2d Mon Sep 17 00:00:00 2001 From: Yuhao Ju Date: Wed, 30 Nov 2022 19:19:00 +0800 Subject: [PATCH 28/56] =?UTF-8?q?update=200110.=E5=B9=B3=E8=A1=A1=E4=BA=8C?= =?UTF-8?q?=E5=8F=89=E6=A0=91:=20=E6=9B=BF=E6=8D=A2=20go=20=E4=BB=A3?= =?UTF-8?q?=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- problems/0110.平衡二叉树.md | 39 ++++++++++++++------------------ 1 file changed, 17 insertions(+), 22 deletions(-) diff --git a/problems/0110.平衡二叉树.md b/problems/0110.平衡二叉树.md index 6e7c8c53..83e4dc4f 100644 --- a/problems/0110.平衡二叉树.md +++ b/problems/0110.平衡二叉树.md @@ -158,7 +158,7 @@ if (node == NULL) { 如何判断以当前传入节点为根节点的二叉树是否是平衡二叉树呢?当然是其左子树高度和其右子树高度的差值。 -分别求出其左右子树的高度,然后如果差值小于等于1,则返回当前二叉树的高度,否则则返回-1,表示已经不是二叉平衡树了。 +分别求出其左右子树的高度,然后如果差值小于等于1,则返回当前二叉树的高度,否则返回-1,表示已经不是二叉平衡树了。 代码如下: @@ -342,7 +342,7 @@ public: **例如:都知道回溯法其实就是递归,但是很少人用迭代的方式去实现回溯算法!** -因为对于回溯算法已经是非常复杂的递归了,如果在用迭代的话,就是自己给自己找麻烦,效率也并不一定高。 +因为对于回溯算法已经是非常复杂的递归了,如果再用迭代的话,就是自己给自己找麻烦,效率也并不一定高。 ## 总结 @@ -559,37 +559,32 @@ class Solution: ### Go ```Go func isBalanced(root *TreeNode) bool { - if root==nil{ - return true - } - if !isBalanced(root.Left) || !isBalanced(root.Right){ - return false - } - LeftH:=maxdepth(root.Left)+1 - RightH:=maxdepth(root.Right)+1 - if abs(LeftH-RightH)>1{ + h := getHeight(root) + if h == -1 { return false } return true } -func maxdepth(root *TreeNode)int{ - if root==nil{ +// 返回以该节点为根节点的二叉树的高度,如果不是平衡二叉树了则返回-1 +func getHeight(root *TreeNode) int { + if root == nil { return 0 } - return max(maxdepth(root.Left),maxdepth(root.Right))+1 + l, r := getHeight(root.Left), getHeight(root.Right) + if l == -1 || r == -1 { + return -1 + } + if l - r > 1 || r - l > 1 { + return -1 + } + return max(l, r) + 1 } -func max(a,b int)int{ - if a>b{ +func max(a, b int) int { + if a > b { return a } return b } -func abs(a int)int{ - if a<0{ - return -a - } - return a -} ``` ### JavaScript From a0115aa88a45be202631cf856fad8065379c195d Mon Sep 17 00:00:00 2001 From: Yuhao Ju Date: Wed, 30 Nov 2022 23:43:42 +0800 Subject: [PATCH 29/56] =?UTF-8?q?update=200257.=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=E4=BC=98?= =?UTF-8?q?=E5=8C=96=20js=20=E4=BB=A3=E7=A0=81=E6=A0=BC=E5=BC=8F=E5=92=8C?= =?UTF-8?q?=E9=94=99=E5=AD=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- problems/0257.二叉树的所有路径.md | 48 +++++++++++------------ 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/problems/0257.二叉树的所有路径.md b/problems/0257.二叉树的所有路径.md index 297acb60..100531cb 100644 --- a/problems/0257.二叉树的所有路径.md +++ b/problems/0257.二叉树的所有路径.md @@ -24,7 +24,7 @@ 这道题目要求从根节点到叶子的路径,所以需要前序遍历,这样才方便让父节点指向孩子节点,找到对应的路径。 -在这道题目中将第一次涉及到回溯,因为我们要把路径记录下来,需要回溯来回退一一个路径在进入另一个路径。 +在这道题目中将第一次涉及到回溯,因为我们要把路径记录下来,需要回溯来回退一个路径再进入另一个路径。 前序遍历以及回溯的过程如图: @@ -44,7 +44,7 @@ void traversal(TreeNode* cur, vector& path, vector& result) 2. 确定递归终止条件 -再写递归的时候都习惯了这么写: +在写递归的时候都习惯了这么写: ``` if (cur == NULL) { @@ -67,7 +67,7 @@ if (cur->left == NULL && cur->right == NULL) { 再来看一下终止处理的逻辑。 -这里使用vector 结构path来记录路径,所以要把vector 结构的path转为string格式,在把这个string 放进 result里。 +这里使用vector 结构path来记录路径,所以要把vector 结构的path转为string格式,再把这个string 放进 result里。 **那么为什么使用了vector 结构来记录路径呢?** 因为在下面处理单层递归逻辑的时候,要做回溯,使用vector方便来做回溯。 @@ -123,7 +123,7 @@ if (cur->right) { path.pop_back(); ``` -这个回溯就要很大的问题,我们知道,**回溯和递归是一一对应的,有一个递归,就要有一个回溯**,这么写的话相当于把递归和回溯拆开了, 一个在花括号里,一个在花括号外。 +这个回溯就有很大的问题,我们知道,**回溯和递归是一一对应的,有一个递归,就要有一个回溯**,这么写的话相当于把递归和回溯拆开了, 一个在花括号里,一个在花括号外。 **所以回溯要和递归永远在一起,世界上最遥远的距离是你在花括号里,而我在花括号外!** @@ -300,16 +300,16 @@ public: ``` -**大家应该可以感受出来,如果把 `path + "->"`作为函数参数就是可以的,因为并有没有改变path的数值,执行完递归函数之后,path依然是之前的数值(相当于回溯了)** +**大家应该可以感受出来,如果把 `path + "->"`作为函数参数就是可以的,因为并没有改变path的数值,执行完递归函数之后,path依然是之前的数值(相当于回溯了)** -**综合以上,第二种递归的代码虽然精简但把很多重要的点隐藏在了代码细节里,第一种递归写法虽然代码多一些,但是把每一个逻辑处理都完整的展现了出来了。** +**综合以上,第二种递归的代码虽然精简但把很多重要的点隐藏在了代码细节里,第一种递归写法虽然代码多一些,但是把每一个逻辑处理都完整的展现出来了。** ## 拓展 这里讲解本题解的写法逻辑以及一些更具体的细节,下面的讲解中,涉及到C++语法特性,如果不是C++的录友,就可以不看了,避免越看越晕。 -如果是C++的录友,建议本题独立刷过两遍,在看下面的讲解,同样避免越看越晕,造成不必要的负担。 +如果是C++的录友,建议本题独立刷过两遍,再看下面的讲解,同样避免越看越晕,造成不必要的负担。 在第二版本的代码中,其实仅仅是回溯了 `->` 部分(调用两次pop_back,一个pop`>` 一次pop`-`),大家应该疑惑那么 `path += to_string(cur->val);` 这一步为什么没有回溯呢? 一条路径能持续加节点 不做回溯吗? @@ -378,7 +378,7 @@ public: 最后我依然给出了迭代法。 -对于本地充分了解递归与回溯的过程之后,有精力的同学可以在去实现迭代法。 +对于本题充分了解递归与回溯的过程之后,有精力的同学可以再去实现迭代法。 @@ -386,7 +386,7 @@ public: # 其他语言版本 -Java: +## Java: ```Java //解法一 @@ -466,7 +466,7 @@ class Solution { } ``` --- -Python: +## Python: 递归法+隐形回溯 ```Python3 # Definition for a binary tree node. @@ -529,7 +529,7 @@ class Solution: --- -Go: +## Go: 递归法: @@ -591,28 +591,28 @@ func binaryTreePaths(root *TreeNode) []string { ``` --- -JavaScript: +## JavaScript: 递归法: ```javascript var binaryTreePaths = function(root) { //递归遍历+递归三部曲 - let res=[]; + let res = []; //1. 确定递归函数 函数参数 - const getPath=function(node,curPath){ + const getPath = function(node,curPath) { //2. 确定终止条件,到叶子节点就终止 - if(node.left===null&&node.right===null){ - curPath+=node.val; + if(node.left === null && node.right === null) { + curPath += node.val; res.push(curPath); - return ; + return; } //3. 确定单层递归逻辑 - curPath+=node.val+'->'; - node.left&&getPath(node.left,curPath); - node.right&&getPath(node.right,curPath); + curPath += node.val + '->'; + node.left && getPath(node.left, curPath); + node.right && getPath(node.right, curPath); } - getPath(root,''); + getPath(root, ''); return res; }; ``` @@ -644,7 +644,7 @@ var binaryTreePaths = function(root) { }; ``` -TypeScript: +## TypeScript: > 递归法 @@ -698,7 +698,7 @@ function binaryTreePaths(root: TreeNode | null): string[] { }; ``` -Swift: +## Swift: > 递归/回溯 ```swift @@ -765,7 +765,7 @@ func binaryTreePaths(_ root: TreeNode?) -> [String] { } ``` -Scala: +## Scala: 递归: ```scala From e8978ea6a852d568314488583eca552b1c14bce1 Mon Sep 17 00:00:00 2001 From: Yuhao Ju Date: Sat, 3 Dec 2022 00:41:43 +0800 Subject: [PATCH 30/56] =?UTF-8?q?update=200404.=E5=B7=A6=E5=8F=B6=E5=AD=90?= =?UTF-8?q?=E4=B9=8B=E5=92=8C:=20=E4=BF=AE=E6=94=B9=20go=20=E4=BB=A3?= =?UTF-8?q?=E7=A0=81=EF=BC=8C=E4=BC=98=E5=8C=96=20js=20=E4=BB=A3=E7=A0=81?= =?UTF-8?q?=E9=A3=8E=E6=A0=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- problems/0404.左叶子之和.md | 83 ++++++++++++++++---------------- 1 file changed, 42 insertions(+), 41 deletions(-) diff --git a/problems/0404.左叶子之和.md b/problems/0404.左叶子之和.md index 6b6fe729..e7ce882c 100644 --- a/problems/0404.左叶子之和.md +++ b/problems/0404.左叶子之和.md @@ -35,7 +35,7 @@ ![图二](https://code-thinking-1253855093.file.myqcloud.com/pics/20220902165805.png) -相信通过这两个图,大家可以最左叶子的定义有明确理解了。 +相信通过这两个图,大家对最左叶子的定义有明确理解了。 那么**判断当前节点是不是左叶子是无法判断的,必须要通过节点的父节点来判断其左孩子是不是左叶子。** @@ -298,48 +298,49 @@ class Solution: ```go func sumOfLeftLeaves(root *TreeNode) int { - var res int - findLeft(root,&res) - return res -} -func findLeft(root *TreeNode,res *int){ - //左节点 - if root.Left!=nil&&root.Left.Left==nil&&root.Left.Right==nil{ - *res=*res+root.Left.Val + if root == nil { + return 0 } - if root.Left!=nil{ - findLeft(root.Left,res) - } - if root.Right!=nil{ - findLeft(root.Right,res) + leftValue := sumOfLeftLeaves(root.Left) // 左 + + if root.Left != nil && root.Left.Left == nil && root.Left.Right == nil { + leftValue = root.Left.Val // 中 } + + rightValue := sumOfLeftLeaves(root.Right) // 右 + + return leftValue + rightValue } ``` -**迭代法** +**迭代法(前序遍历)** ```go func sumOfLeftLeaves(root *TreeNode) int { - var res int - queue:=list.New() - queue.PushBack(root) - for queue.Len()>0{ - length:=queue.Len() - for i:=0;i Date: Sat, 3 Dec 2022 10:04:19 +0800 Subject: [PATCH 31/56] =?UTF-8?q?update=200513.=E6=89=BE=E6=A0=91=E5=B7=A6?= =?UTF-8?q?=E4=B8=8B=E8=A7=92=E7=9A=84=E5=80=BC=20=E4=BC=98=E5=8C=96=20go?= =?UTF-8?q?=20=E5=92=8C=20js=20=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- problems/0513.找树左下角的值.md | 91 ++++++++++++-------------- 1 file changed, 42 insertions(+), 49 deletions(-) diff --git a/problems/0513.找树左下角的值.md b/problems/0513.找树左下角的值.md index fd6e5d95..025d954d 100644 --- a/problems/0513.找树左下角的值.md +++ b/problems/0513.找树左下角的值.md @@ -26,7 +26,7 @@ ## 思路 -本地要找出树的最后一行找到最左边的值。此时大家应该想起用层序遍历是非常简单的了,反而用递归的话会比较难一点。 +本题要找出树的最后一行的最左边的值。此时大家应该想起用层序遍历是非常简单的了,反而用递归的话会比较难一点。 我们依然还是先介绍递归法。 @@ -46,7 +46,7 @@ 所以要找深度最大的叶子节点。 -那么如果找最左边的呢?可以使用前序遍历(当然中序,后序都可以,因为本题没有 中间节点的处理逻辑,只要左优先就行),保证优先左边搜索,然后记录深度最大的叶子节点,此时就是树的最后一行最左边的值。 +那么如何找最左边的呢?可以使用前序遍历(当然中序,后序都可以,因为本题没有 中间节点的处理逻辑,只要左优先就行),保证优先左边搜索,然后记录深度最大的叶子节点,此时就是树的最后一行最左边的值。 递归三部曲: @@ -169,7 +169,7 @@ public: ### 迭代法 -本题使用层序遍历再合适不过了,比递归要好理解的多! +本题使用层序遍历再合适不过了,比递归要好理解得多! 只需要记录最后一行第一个节点的数值就可以了。 @@ -323,34 +323,25 @@ class Solution: 递归法: ```go - var maxDeep int // 全局变量 深度 - var value int //全局变量 最终值 +var depth int // 全局变量 最大深度 +var res int // 记录最终结果 func findBottomLeftValue(root *TreeNode) int { - if root.Left==nil&&root.Right==nil{//需要提前判断一下(不要这个if的话提交结果会出错,但执行代码不会。防止这种情况出现,故先判断是否只有一个节点) - return root.Val - } - findLeftValue (root,maxDeep) - return value + depth, res = 0, 0 // 初始化 + dfs(root, 1) + return res } -func findLeftValue (root *TreeNode,deep int){ - //最左边的值在左边 - if root.Left==nil&&root.Right==nil{ - if deep>maxDeep{ - value=root.Val - maxDeep=deep - } - } - //递归 - if root.Left!=nil{ - deep++ - findLeftValue(root.Left,deep) - deep--//回溯 + +func dfs(root *TreeNode, d int) { + if root == nil { + return } - if root.Right!=nil{ - deep++ - findLeftValue(root.Right,deep) - deep--//回溯 + // 因为先遍历左边,所以左边如果有值,右边的同层不会更新结果 + if root.Left == nil && root.Right == nil && depth < d { + depth = d + res = root.Val } + dfs(root.Left, d+1) // 隐藏回溯 + dfs(root.Right, d+1) } ``` @@ -358,18 +349,21 @@ func findLeftValue (root *TreeNode,deep int){ ```go func findBottomLeftValue(root *TreeNode) int { - queue:=list.New() var gradation int + queue := list.New() + queue.PushBack(root) - for queue.Len()>0{ - length:=queue.Len() - for i:=0;i 0 { + length := queue.Len() + for i := 0; i < length; i++ { + node := queue.Remove(queue.Front()).(*TreeNode) + if i == 0 { + gradation = node.Val + } + if node.Left != nil { queue.PushBack(node.Left) } - if node.Right!=nil{ + if node.Right != nil { queue.PushBack(node.Right) } } @@ -385,19 +379,18 @@ func findBottomLeftValue(root *TreeNode) int { ```javascript var findBottomLeftValue = function(root) { //首先考虑递归遍历 前序遍历 找到最大深度的叶子节点即可 - let maxPath = 0,resNode = null; + let maxPath = 0, resNode = null; // 1. 确定递归函数的函数参数 - const dfsTree = function(node,curPath){ + const dfsTree = function(node, curPath) { // 2. 确定递归函数终止条件 - if(node.left===null&&node.right===null){ - if(curPath>maxPath){ + if(node.left === null && node.right === null) { + if(curPath > maxPath) { maxPath = curPath; resNode = node.val; } - // return ; } - node.left&&dfsTree(node.left,curPath+1); - node.right&&dfsTree(node.right,curPath+1); + node.left && dfsTree(node.left, curPath+1); + node.right && dfsTree(node.right, curPath+1); } dfsTree(root,1); return resNode; @@ -409,20 +402,20 @@ var findBottomLeftValue = function(root) { var findBottomLeftValue = function(root) { //考虑层序遍历 记录最后一行的第一个节点 let queue = []; - if(root===null){ + if(root === null) { return null; } queue.push(root); let resNode; - while(queue.length){ - let length = queue.length; - for(let i=0; i Date: Sat, 3 Dec 2022 10:29:45 +0800 Subject: [PATCH 32/56] =?UTF-8?q?update=200112.=E8=B7=AF=E5=BE=84=E6=80=BB?= =?UTF-8?q?=E5=92=8C:=20=E4=BC=98=E5=8C=96=20java=20=E5=92=8C=20js=20?= =?UTF-8?q?=E9=83=A8=E5=88=86=E4=BB=A3=E7=A0=81=E6=A0=BC=E5=BC=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- problems/0112.路径总和.md | 54 +++++++++++++++++++---------------- 1 file changed, 30 insertions(+), 24 deletions(-) diff --git a/problems/0112.路径总和.md b/problems/0112.路径总和.md index d50f23f9..cb9d343f 100644 --- a/problems/0112.路径总和.md +++ b/problems/0112.路径总和.md @@ -33,7 +33,7 @@ * 112.路径总和 * 113.路径总和ii -这道题我们要遍历从根节点到叶子节点的的路径看看总和是不是目标和。 +这道题我们要遍历从根节点到叶子节点的路径看看总和是不是目标和。 ### 递归 @@ -167,7 +167,7 @@ public: }; ``` -**是不是发现精简之后的代码,已经完全看不出分析的过程了,所以我们要把题目分析清楚之后,在追求代码精简。** 这一点我已经强调很多次了! +**是不是发现精简之后的代码,已经完全看不出分析的过程了,所以我们要把题目分析清楚之后,再追求代码精简。** 这一点我已经强调很多次了! ### 迭代 @@ -316,13 +316,13 @@ class solution { } if (root.left != null) { boolean left = haspathsum(root.left, targetsum); - if (left) {// 已经找到 + if (left) { // 已经找到 return true; } } if (root.right != null) { boolean right = haspathsum(root.right, targetsum); - if (right) {// 已经找到 + if (right) { // 已经找到 return true; } } @@ -348,31 +348,37 @@ class solution { ```java class solution { public boolean haspathsum(treenode root, int targetsum) { - if(root==null)return false; + if(root == null) return false; stack stack1 = new stack<>(); stack stack2 = new stack<>(); - stack1.push(root);stack2.push(root.val); - while(!stack1.isempty()){ + stack1.push(root); + stack2.push(root.val); + while(!stack1.isempty()) { int size = stack1.size(); - for(int i=0;i Date: Sat, 3 Dec 2022 10:51:01 +0800 Subject: [PATCH 33/56] =?UTF-8?q?update=200106.=E4=BB=8E=E4=B8=AD=E5=BA=8F?= =?UTF-8?q?=E4=B8=8E=E5=90=8E=E5=BA=8F=E9=81=8D=E5=8E=86=E5=BA=8F=E5=88=97?= =?UTF-8?q?=E6=9E=84=E9=80=A0=E4=BA=8C=E5=8F=89=E6=A0=91:=20=E6=9B=B4?= =?UTF-8?q?=E6=96=B0=20go=20=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...序与后序遍历序列构造二叉树.md | 75 +++++++++++-------- 1 file changed, 44 insertions(+), 31 deletions(-) diff --git a/problems/0106.从中序与后序遍历序列构造二叉树.md b/problems/0106.从中序与后序遍历序列构造二叉树.md index 17ba561d..94eb405b 100644 --- a/problems/0106.从中序与后序遍历序列构造二叉树.md +++ b/problems/0106.从中序与后序遍历序列构造二叉树.md @@ -34,7 +34,7 @@ ## 思路 -首先回忆一下如何根据两个顺序构造一个唯一的二叉树,相信理论知识大家应该都清楚,就是以 后序数组的最后一个元素为切割点,先切中序数组,根据中序数组,反过来在切后序数组。一层一层切下去,每次后序数组最后一个元素就是节点元素。 +首先回忆一下如何根据两个顺序构造一个唯一的二叉树,相信理论知识大家应该都清楚,就是以 后序数组的最后一个元素为切割点,先切中序数组,根据中序数组,反过来再切后序数组。一层一层切下去,每次后序数组最后一个元素就是节点元素。 如果让我们肉眼看两个序列,画一棵二叉树的话,应该分分钟都可以画出来。 @@ -236,7 +236,7 @@ private: vector leftPostorder(postorder.begin(), postorder.begin() + leftInorder.size()); vector rightPostorder(postorder.begin() + leftInorder.size(), postorder.end()); - // 一下为日志 + // 以下为日志 cout << "----------" << endl; cout << "leftInorder :"; @@ -275,7 +275,7 @@ public: }; ``` -**此时应该发现了,如上的代码性能并不好,应为每层递归定定义了新的vector(就是数组),既耗时又耗空间,但上面的代码是最好理解的,为了方便读者理解,所以用如上的代码来讲解。** +**此时应该发现了,如上的代码性能并不好,因为每层递归定义了新的vector(就是数组),既耗时又耗空间,但上面的代码是最好理解的,为了方便读者理解,所以用如上的代码来讲解。** 下面给出用下标索引写出的代码版本:(思路是一样的,只不过不用重复定义vector了,每次用下标索引来分割) @@ -569,7 +569,7 @@ tree2 的前序遍历是[1 2 3], 后序遍历是[3 2 1]。 之前我们讲的二叉树题目都是各种遍历二叉树,这次开始构造二叉树了,思路其实比较简单,但是真正代码实现出来并不容易。 -所以要避免眼高手低,踏实的把代码写出来。 +所以要避免眼高手低,踏实地把代码写出来。 我同时给出了添加日志的代码版本,因为这种题目是不太容易写出来调一调就能过的,所以一定要把流程日志打出来,看看符不符合自己的思路。 @@ -728,25 +728,33 @@ class Solution: * Right *TreeNode * } */ +var ( + hash map[int]int +) func buildTree(inorder []int, postorder []int) *TreeNode { - if len(inorder)<1||len(postorder)<1{return nil} - //先找到根节点(后续遍历的最后一个就是根节点) - nodeValue:=postorder[len(postorder)-1] - //从中序遍历中找到一分为二的点,左边为左子树,右边为右子树 - left:=findRootIndex(inorder,nodeValue) - //构造root - root:=&TreeNode{Val: nodeValue, - Left: buildTree(inorder[:left],postorder[:left]),//将后续遍历一分为二,左边为左子树,右边为右子树 - Right: buildTree(inorder[left+1:],postorder[left:len(postorder)-1])} + hash = make(map[int]int) + for i, v := range inorder { // 用map保存中序序列的数值对应位置 + hash[v] = i + } + // 以左闭右闭的原则进行切分 + root := rebuild(inorder, postorder, len(postorder)-1, 0, len(inorder)-1) return root } -func findRootIndex(inorder []int,target int) (index int){ - for i:=0;i r { // 说明没有元素,返回空树 + return nil } - return -1 + if l == r { // 只剩唯一一个元素,直接返回 + return &TreeNode{Val : inorder[l]} + } + rootV := postorder[rootIdx] // 根据后序数组找到根节点的值 + rootIn := hash[rootV] // 找到根节点在对应的中序数组中的位置 + root := &TreeNode{Val : rootV} // 构造根节点 + // 重建左节点和右节点 + root.Left = rebuild(inorder, postorder, rootIdx-(r-rootIn)-1, l, rootIn-1) + root.Right = rebuild(inorder, postorder, rootIdx-1, rootIn+1, r) + return root } ``` @@ -761,22 +769,27 @@ func findRootIndex(inorder []int,target int) (index int){ * Right *TreeNode * } */ +var ( + hash map[int]int +) func buildTree(preorder []int, inorder []int) *TreeNode { - if len(preorder)<1||len(inorder)<1{return nil} - left:=findRootIndex(preorder[0],inorder) - root:=&TreeNode{ - Val: preorder[0], - Left: buildTree(preorder[1:left+1],inorder[:left]), - Right: buildTree(preorder[left+1:],inorder[left+1:])} + hash = make(map[int]int, len(inorder)) + for i, v := range inorder { + hash[v] = i + } + root := build(preorder, inorder, 0, 0, len(inorder)-1) // l, r 表示构造的树在中序遍历数组中的范围 return root } -func findRootIndex(target int,inorder []int) int{ - for i:=0;i r { + return nil } - return -1 + rootVal := pre[root] // 找到本次构造的树的根节点 + index := hash[rootVal] // 根节点在中序数组中的位置 + node := &TreeNode {Val: rootVal} + node.Left = build(pre, in, root + 1, l, index-1) + node.Right = build(pre, in, root + (index-l) + 1, index+1, r) + return node } ``` From 770babda32822cc9dd7d5a66b5971bbbd97d0c44 Mon Sep 17 00:00:00 2001 From: Yuhao Ju Date: Sun, 4 Dec 2022 11:13:58 +0800 Subject: [PATCH 34/56] =?UTF-8?q?update=200654.=E6=9C=80=E5=A4=A7=E4=BA=8C?= =?UTF-8?q?=E5=8F=89=E6=A0=91:=20=E6=9B=B4=E6=96=B0=20go=20=E4=BB=A3?= =?UTF-8?q?=E7=A0=81=E9=A3=8E=E6=A0=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- problems/0654.最大二叉树.md | 34 +++++++++++++------------------- 1 file changed, 14 insertions(+), 20 deletions(-) diff --git a/problems/0654.最大二叉树.md b/problems/0654.最大二叉树.md index fda64372..ebb5e2a4 100644 --- a/problems/0654.最大二叉树.md +++ b/problems/0654.最大二叉树.md @@ -40,7 +40,7 @@ * 确定递归函数的参数和返回值 -参数就是传入的是存放元素的数组,返回该数组构造的二叉树的头结点,返回类型是指向节点的指针。 +参数传入的是存放元素的数组,返回该数组构造的二叉树的头结点,返回类型是指向节点的指针。 代码如下: @@ -309,30 +309,24 @@ class Solution: ```go -/** - * Definition for a binary tree node. - * type TreeNode struct { - * Val int - * Left *TreeNode - * Right *TreeNode - * } - */ func constructMaximumBinaryTree(nums []int) *TreeNode { - if len(nums)<1{return nil} - //首选找到最大值 - index:=findMax(nums) - //其次构造二叉树 - root:=&TreeNode{ + if len(nums) == 0 { + return nil + } + // 找到最大值 + index := findMax(nums) + // 构造二叉树 + root := &TreeNode { Val: nums[index], - Left:constructMaximumBinaryTree(nums[:index]),//左半边 - Right:constructMaximumBinaryTree(nums[index+1:]),//右半边 + Left: constructMaximumBinaryTree(nums[:index]), //左半边 + Right: constructMaximumBinaryTree(nums[index+1:]),//右半边 } return root } -func findMax(nums []int) (index int){ - for i:=0;inums[index]{ - index=i +func findMax(nums []int) (index int) { + for i, v := range nums { + if nums[index] < v { + index = i } } return From b81abd3d6b444e256e6ed3b4f19e650f131f6732 Mon Sep 17 00:00:00 2001 From: Yuhao Ju Date: Sun, 4 Dec 2022 11:44:01 +0800 Subject: [PATCH 35/56] =?UTF-8?q?update=200617.=E5=90=88=E5=B9=B6=E4=BA=8C?= =?UTF-8?q?=E5=8F=89=E6=A0=91:=20=E4=BC=98=E5=8C=96=20go=20=E4=BB=A3?= =?UTF-8?q?=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- problems/0617.合并二叉树.md | 64 +++++++------------------------- 1 file changed, 14 insertions(+), 50 deletions(-) diff --git a/problems/0617.合并二叉树.md b/problems/0617.合并二叉树.md index db2d3762..58701b7d 100644 --- a/problems/0617.合并二叉树.md +++ b/problems/0617.合并二叉树.md @@ -46,7 +46,7 @@ 1. **确定递归函数的参数和返回值:** -首先那么要合入两个二叉树,那么参数至少是要传入两个二叉树的根节点,返回值就是合并之后二叉树的根节点。 +首先要合入两个二叉树,那么参数至少是要传入两个二叉树的根节点,返回值就是合并之后二叉树的根节点。 代码如下: @@ -56,7 +56,7 @@ TreeNode* mergeTrees(TreeNode* t1, TreeNode* t2) { 2. **确定终止条件:** -因为是传入了两个树,那么就有两个树遍历的节点t1 和 t2,如果t1 == NULL 了,两个树合并就应该是 t2 了啊(如果t2也为NULL也无所谓,合并之后就是NULL)。 +因为是传入了两个树,那么就有两个树遍历的节点t1 和 t2,如果t1 == NULL 了,两个树合并就应该是 t2 了(如果t2也为NULL也无所谓,合并之后就是NULL)。 反过来如果t2 == NULL,那么两个数合并就是t1(如果t1也为NULL也无所谓,合并之后就是NULL)。 @@ -70,7 +70,7 @@ if (t2 == NULL) return t1; // 如果t2为空,合并之后就应该是t1 3. **确定单层递归的逻辑:** -单层递归的逻辑就比较好些了,这里我们用重复利用一下t1这个树,t1就是合并之后树的根节点(就是修改了原来树的结构)。 +单层递归的逻辑就比较好写了,这里我们重复利用一下t1这个树,t1就是合并之后树的根节点(就是修改了原来树的结构)。 那么单层递归中,就要把两棵树的元素加到一起。 ``` @@ -144,7 +144,7 @@ public: **但是前序遍历是最好理解的,我建议大家用前序遍历来做就OK。** -如上的方法修改了t1的结构,当然也可以不修改t1和t2的结构,重新定一个树。 +如上的方法修改了t1的结构,当然也可以不修改t1和t2的结构,重新定义一个树。 不修改输入树的结构,前序遍历,代码如下: @@ -214,7 +214,7 @@ public: ## 拓展 -当然也可以秀一波指针的操作,这是我写的野路子,大家就随便看看就行了,以防带跑遍了。 +当然也可以秀一波指针的操作,这是我写的野路子,大家就随便看看就行了,以防带跑偏了。 如下代码中,想要更改二叉树的值,应该传入指向指针的指针。 @@ -252,7 +252,7 @@ public: 迭代法中,一般一起操作两个树都是使用队列模拟类似层序遍历,同时处理两个树的节点,这种方式最好理解,如果用模拟递归的思路的话,要复杂一些。 -最后拓展中,我给了一个操作指针的野路子,大家随便看看就行了,如果学习C++的话,可以在去研究研究。 +最后拓展中,我给了一个操作指针的野路子,大家随便看看就行了,如果学习C++的话,可以再去研究研究。 ## 其他语言版本 @@ -417,43 +417,7 @@ class Solution: ### Go ```go -/** - * Definition for a binary tree node. - * type TreeNode struct { - * Val int - * Left *TreeNode - * Right *TreeNode - * } - */ - //前序遍历(递归遍历,跟105 106差不多的思路) -func mergeTrees(t1 *TreeNode, t2 *TreeNode) *TreeNode { - var value int - var nullNode *TreeNode//空node,便于遍历 - nullNode=&TreeNode{ - Val:0, - Left:nil, - Right:nil} - switch { - case t1==nil&&t2==nil: return nil//终止条件 - default : //如果其中一个节点为空,则将该节点置为nullNode,方便下次遍历 - if t1==nil{ - value=t2.Val - t1=nullNode - }else if t2==nil{ - value=t1.Val - t2=nullNode - }else { - value=t1.Val+t2.Val - } - } - root:=&TreeNode{//构造新的二叉树 - Val: value, - Left: mergeTrees(t1.Left,t2.Left), - Right: mergeTrees(t1.Right,t2.Right)} - return root -} - -// 前序遍历简洁版 +// 前序遍历 func mergeTrees(root1 *TreeNode, root2 *TreeNode) *TreeNode { if root1 == nil { return root2 @@ -479,28 +443,28 @@ func mergeTrees(root1 *TreeNode, root2 *TreeNode) *TreeNode { queue = append(queue,root1) queue = append(queue,root2) - for size:=len(queue);size>0;size=len(queue){ + for size := len(queue); size>0; size=len(queue) { node1 := queue[0] queue = queue[1:] node2 := queue[0] queue = queue[1:] node1.Val += node2.Val // 左子树都不为空 - if node1.Left != nil && node2.Left != nil{ + if node1.Left != nil && node2.Left != nil { queue = append(queue,node1.Left) queue = append(queue,node2.Left) } // 右子树都不为空 - if node1.Right !=nil && node2.Right !=nil{ - queue = append(queue,node1.Right) - queue = append(queue,node2.Right) + if node1.Right !=nil && node2.Right !=nil { + queue = append(queue, node1.Right) + queue = append(queue, node2.Right) } // 树 1 的左子树为 nil,直接接上树 2 的左子树 - if node1.Left == nil{ + if node1.Left == nil { node1.Left = node2.Left } // 树 1 的右子树为 nil,直接接上树 2 的右子树 - if node1.Right == nil{ + if node1.Right == nil { node1.Right = node2.Right } } From a85036e81126de1b026772ef803776a56540946c Mon Sep 17 00:00:00 2001 From: Yuhao Ju Date: Sun, 4 Dec 2022 12:24:34 +0800 Subject: [PATCH 36/56] =?UTF-8?q?update=200700.=E4=BA=8C=E5=8F=89=E6=90=9C?= =?UTF-8?q?=E7=B4=A2=E6=A0=91=E4=B8=AD=E7=9A=84=E6=90=9C=E7=B4=A2:=20?= =?UTF-8?q?=E4=BF=AE=E6=94=B9=20go=20=E7=9A=84=E8=BF=AD=E4=BB=A3=E6=B3=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- problems/0700.二叉搜索树中的搜索.md | 24 ++++++++++---------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/problems/0700.二叉搜索树中的搜索.md b/problems/0700.二叉搜索树中的搜索.md index 2ee2bdb0..f40f778a 100644 --- a/problems/0700.二叉搜索树中的搜索.md +++ b/problems/0700.二叉搜索树中的搜索.md @@ -24,7 +24,7 @@ ## 思路 -之前我们讲了都是普通二叉树,那么接下来看看二叉搜索树。 +之前我们讲的都是普通二叉树,那么接下来看看二叉搜索树。 在[关于二叉树,你该了解这些!](https://programmercarl.com/二叉树理论基础.html)中,我们已经讲过了二叉搜索树。 @@ -269,13 +269,13 @@ class Solution: ```go //递归法 func searchBST(root *TreeNode, val int) *TreeNode { - if root==nil||root.Val==val{ + if root == nil || root.Val == val { return root } - if root.Val>val{ - return searchBST(root.Left,val) + if root.Val > val { + return searchBST(root.Left, val) } - return searchBST(root.Right,val) + return searchBST(root.Right, val) } ``` @@ -284,13 +284,13 @@ func searchBST(root *TreeNode, val int) *TreeNode { ```go //迭代法 func searchBST(root *TreeNode, val int) *TreeNode { - for root!=nil{ - if root.Val>val{ - root=root.Left - }else if root.Val val { + root = root.Left + } else if root.Val < val { + root = root.Right + } else { + return root } } return nil From d32e8f54c8803c475ab403fc1fa918b7e74b2a8e Mon Sep 17 00:00:00 2001 From: Yuhao Ju Date: Sun, 4 Dec 2022 13:52:36 +0800 Subject: [PATCH 37/56] =?UTF-8?q?update=200098.=E9=AA=8C=E8=AF=81=E4=BA=8C?= =?UTF-8?q?=E5=8F=89=E6=90=9C=E7=B4=A2=E6=A0=91:=20=E4=BF=AE=E6=94=B9?= =?UTF-8?q?=E6=96=87=E6=9C=AC=E9=94=99=E8=AF=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- problems/0098.验证二叉搜索树.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/problems/0098.验证二叉搜索树.md b/problems/0098.验证二叉搜索树.md index bb38ae35..db9c28ad 100644 --- a/problems/0098.验证二叉搜索树.md +++ b/problems/0098.验证二叉搜索树.md @@ -437,8 +437,6 @@ class Solution: ## Go ```Go -import "math" - func isValidBST(root *TreeNode) bool { // 二叉搜索树也可以是空树 if root == nil { From a4d7ed61422dfef71149443eb84d3a8cb074a1b6 Mon Sep 17 00:00:00 2001 From: Yuhao Ju Date: Sun, 4 Dec 2022 14:27:21 +0800 Subject: [PATCH 38/56] =?UTF-8?q?update=200530.=E4=BA=8C=E5=8F=89=E6=90=9C?= =?UTF-8?q?=E7=B4=A2=E6=A0=91=E7=9A=84=E6=9C=80=E5=B0=8F=E7=BB=9D=E5=AF=B9?= =?UTF-8?q?=E5=B7=AE:=20=E5=88=A0=E9=99=A4=20go=20=E5=86=97=E4=BD=99?= =?UTF-8?q?=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../0530.二叉搜索树的最小绝对差.md | 22 ------------------- 1 file changed, 22 deletions(-) diff --git a/problems/0530.二叉搜索树的最小绝对差.md b/problems/0530.二叉搜索树的最小绝对差.md index ad4f46d8..699afcf7 100644 --- a/problems/0530.二叉搜索树的最小绝对差.md +++ b/problems/0530.二叉搜索树的最小绝对差.md @@ -248,28 +248,6 @@ class Solution: ## Go: 中序遍历,然后计算最小差值 - -```go -func getMinimumDifference(root *TreeNode) int { - var res []int - findMIn(root,&res) - min:=1000000//一个比较大的值 - for i:=1;i Date: Sun, 4 Dec 2022 15:31:13 +0800 Subject: [PATCH 39/56] =?UTF-8?q?update=200501.=E4=BA=8C=E5=8F=89=E6=90=9C?= =?UTF-8?q?=E7=B4=A2=E6=A0=91=E4=B8=AD=E7=9A=84=E4=BC=97=E6=95=B0:=20?= =?UTF-8?q?=E4=BF=AE=E6=94=B9=20java=EF=BC=8Cgo=20=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- problems/0501.二叉搜索树中的众数.md | 45 ++------------------ 1 file changed, 3 insertions(+), 42 deletions(-) diff --git a/problems/0501.二叉搜索树中的众数.md b/problems/0501.二叉搜索树中的众数.md index 3c6362bf..f016ee58 100644 --- a/problems/0501.二叉搜索树中的众数.md +++ b/problems/0501.二叉搜索树中的众数.md @@ -54,7 +54,7 @@ 1. 这个树都遍历了,用map统计频率 -至于用前中后序那种遍历也不重要,因为就是要全遍历一遍,怎么个遍历法都行,层序遍历都没毛病! +至于用前中后序哪种遍历也不重要,因为就是要全遍历一遍,怎么个遍历法都行,层序遍历都没毛病! 这里采用前序遍历,代码如下: @@ -354,7 +354,7 @@ public: ```java class Solution { - public int[] findMode(FindModeInBinarySearchTree.TreeNode root) { + public int[] findMode(TreeNode root) { Map map = new HashMap<>(); List list = new ArrayList<>(); if (root == null) return list.stream().mapToInt(Integer::intValue).toArray(); @@ -375,7 +375,7 @@ class Solution { return list.stream().mapToInt(Integer::intValue).toArray(); } - void searchBST(FindModeInBinarySearchTree.TreeNode curr, Map map) { + void searchBST(TreeNode curr, Map map) { if (curr == null) return; map.put(curr.val, map.getOrDefault(curr.val, 0) + 1); searchBST(curr.left, map); @@ -556,46 +556,7 @@ class Solution: ``` ## Go -暴力法(非BSL) - -```go -func findMode(root *TreeNode) []int { - var history map[int]int - var maxValue int - var maxIndex int - var result []int - history=make(map[int]int) - traversal(root,history) - for k,value:=range history{ - if value>maxValue{ - maxValue=value - maxIndex=k - } - } - for k,value:=range history{ - if value==history[maxIndex]{ - result=append(result,k) - } - } - return result -} -func traversal(root *TreeNode,history map[int]int){ - if root.Left!=nil{ - traversal(root.Left,history) - } - if value,ok:=history[root.Val];ok{ - history[root.Val]=value+1 - }else{ - history[root.Val]=1 - } - if root.Right!=nil{ - traversal(root.Right,history) - } -} -``` - 计数法,不使用额外空间,利用二叉树性质,中序遍历 - ```go func findMode(root *TreeNode) []int { res := make([]int, 0) From c5fa95ebffe0cbc200166a6eb914702d398be659 Mon Sep 17 00:00:00 2001 From: Yuhao Ju Date: Sun, 4 Dec 2022 22:55:45 +0800 Subject: [PATCH 40/56] =?UTF-8?q?update=200236.=E4=BA=8C=E5=8F=89=E6=A0=91?= =?UTF-8?q?=E7=9A=84=E6=9C=80=E8=BF=91=E5=85=AC=E5=85=B1=E7=A5=96=E5=85=88?= =?UTF-8?q?=EF=BC=9A=E4=BF=AE=E6=94=B9=E9=94=99=E5=AD=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../0236.二叉树的最近公共祖先.md | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/problems/0236.二叉树的最近公共祖先.md b/problems/0236.二叉树的最近公共祖先.md index a34e8c21..bf2007b5 100644 --- a/problems/0236.二叉树的最近公共祖先.md +++ b/problems/0236.二叉树的最近公共祖先.md @@ -48,7 +48,7 @@ 后序遍历(左右中)就是天然的回溯过程,可以根据左右子树的返回值,来处理中节点的逻辑。 -接下来就看如何判断一个节点是节点q和节点p的公共公共祖先呢。 +接下来就看如何判断一个节点是节点q和节点p的公共祖先呢。 **首先最容易想到的一个情况:如果找到一个节点,发现左子树出现结点p,右子树出现节点q,或者 左子树出现结点q,右子树出现节点p,那么该节点就是节点p和q的最近公共祖先。** 即情况一: @@ -66,9 +66,9 @@ 其实情况一 和 情况二 代码实现过程都是一样的,也可以说,实现情况一的逻辑,顺便包含了情况二。 -因为遇到 q 或者 p 就返回,这样也包含了 q 或者 p 本省就是 公共祖先的情况。 +因为遇到 q 或者 p 就返回,这样也包含了 q 或者 p 本身就是 公共祖先的情况。 -这一点是很多录友容易忽略的,在下面的代码讲解中,可以在去体会。 +这一点是很多录友容易忽略的,在下面的代码讲解中,可以再去体会。 递归三部曲: @@ -86,9 +86,9 @@ TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) * 确定终止条件 -遇到空的话,然后然后空,因为树都是空了,所以返回空。 +遇到空的话,因为树都是空了,所以返回空。 -那么我们来说一说,如果 root == q,或者 root == p,说明找到 q p ,则将其返回,这个返回值,后面在中节点的处理过程中会用到,那么中节点处理逻辑,后下面讲解。 +那么我们来说一说,如果 root == q,或者 root == p,说明找到 q p ,则将其返回,这个返回值,后面在中节点的处理过程中会用到,那么中节点的处理逻辑,下面讲解。 代码如下: @@ -167,7 +167,7 @@ TreeNode* right = lowestCommonAncestor(root->right, p, q); 图中节点10的左子树返回null,右子树返回目标值7,那么此时节点10的处理逻辑就是把右子树的返回值(最近公共祖先7)返回上去! -这里点也很重要,可能刷过这道题目的同学,都不清楚结果究竟是如何从底层一层一层传到头结点的。 +这里也很重要,可能刷过这道题目的同学,都不清楚结果究竟是如何从底层一层一层传到头结点的。 那么如果left和right都为空,则返回left或者right都是可以的,也就是返回空。 @@ -231,7 +231,7 @@ public: **那么我给大家归纳如下三点**: -1. 求最小公共祖先,需要从底向上遍历,那么二叉树,只能通过后序遍历(即:回溯)实现从低向上的遍历方式。 +1. 求最小公共祖先,需要从底向上遍历,那么二叉树,只能通过后序遍历(即:回溯)实现从底向上的遍历方式。 2. 在回溯的过程中,必然要遍历整棵二叉树,即使已经找到结果了,依然要把其他节点遍历完,因为要使用递归函数的返回值(也就是代码中的left和right)做逻辑判断。 @@ -332,16 +332,16 @@ var lowestCommonAncestor = function(root, p, q) { // 1. 确定递归的函数 const travelTree = function(root,p,q) { // 2. 确定递归终止条件 - if(root === null || root === p||root === q) { + if(root === null || root === p || root === q) { return root; } // 3. 确定递归单层逻辑 let left = travelTree(root.left,p,q); let right = travelTree(root.right,p,q); - if(left !== null&&right !== null) { + if(left !== null && right !== null) { return root; } - if(left ===null) { + if(left === null) { return right; } return left; From 1287679e8eedc2c49b5e61946a15445e345b4cf4 Mon Sep 17 00:00:00 2001 From: Yuhao Ju Date: Sun, 4 Dec 2022 23:10:10 +0800 Subject: [PATCH 41/56] =?UTF-8?q?update=200235.=E4=BA=8C=E5=8F=89=E6=90=9C?= =?UTF-8?q?=E7=B4=A2=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=9B=BF=E6=8D=A2=20go=20=E4=BB=A3?= =?UTF-8?q?=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...35.二叉搜索树的最近公共祖先.md | 30 ++++++++++++------- 1 file changed, 19 insertions(+), 11 deletions(-) diff --git a/problems/0235.二叉搜索树的最近公共祖先.md b/problems/0235.二叉搜索树的最近公共祖先.md index c90b3d8c..391d1cfb 100644 --- a/problems/0235.二叉搜索树的最近公共祖先.md +++ b/problems/0235.二叉搜索树的最近公共祖先.md @@ -303,14 +303,22 @@ class Solution: 递归法: ```go -//利用BSL的性质(前序遍历有序) func lowestCommonAncestor(root, p, q *TreeNode) *TreeNode { - if root==nil{return nil} - if root.Val>p.Val&&root.Val>q.Val{//当前节点的值大于给定的值,则说明满足条件的在左边 - return lowestCommonAncestor(root.Left,p,q) - }else if root.Val p.Val && root.Val > q.Val { + root = root.Left + } + if root.Val < p.Val && root.Val < q.Val { + root = root.Right + } + if (root.Val - p.Val) * (root.Val - q.Val) <= 0 { + return root + } + } + return root } ``` @@ -326,11 +334,11 @@ var lowestCommonAncestor = function(root, p, q) { if(root === null) { return root; } - if(root.val>p.val&&root.val>q.val) { + if(root.val > p.val && root.val > q.val) { // 向左子树查询 return root.left = lowestCommonAncestor(root.left,p,q); } - if(root.valp.val&&root.val>q.val) { + if(root.val > p.val && root.val > q.val) { root = root.left; - }else if(root.val Date: Sun, 4 Dec 2022 23:58:10 +0800 Subject: [PATCH 42/56] =?UTF-8?q?update=200701.=E4=BA=8C=E5=8F=89=E6=90=9C?= =?UTF-8?q?=E7=B4=A2=E6=A0=91=E4=B8=AD=E7=9A=84=E6=8F=92=E5=85=A5=E6=93=8D?= =?UTF-8?q?=E4=BD=9C:=20=E4=BF=AE=E6=94=B9=E9=94=99=E5=AD=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- problems/0701.二叉搜索树中的插入操作.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/problems/0701.二叉搜索树中的插入操作.md b/problems/0701.二叉搜索树中的插入操作.md index 2e899e22..432413b6 100644 --- a/problems/0701.二叉搜索树中的插入操作.md +++ b/problems/0701.二叉搜索树中的插入操作.md @@ -24,7 +24,7 @@ # 思路 -其实这道题目其实是一道简单题目,**但是题目中的提示:有多种有效的插入方式,还可以重构二叉搜索树,一下子吓退了不少人**,瞬间感觉题目复杂了很多。 +这道题目其实是一道简单题目,**但是题目中的提示:有多种有效的插入方式,还可以重构二叉搜索树,一下子吓退了不少人**,瞬间感觉题目复杂了很多。 其实**可以不考虑题目中提示所说的改变树的结构的插入方式。** @@ -157,7 +157,7 @@ public: 我之所以举这个例子,是想说明通过递归函数的返回值完成父子节点的赋值是可以带来便利的。 -**网上千变一律的代码,可能会误导大家认为通过递归函数返回节点 这样的写法是天经地义,其实这里是有优化的!** +**网上千篇一律的代码,可能会误导大家认为通过递归函数返回节点 这样的写法是天经地义,其实这里是有优化的!** ## 迭代 @@ -197,7 +197,7 @@ public: 首先在二叉搜索树中的插入操作,大家不用恐惧其重构搜索树,其实根本不用重构。 -然后在递归中,我们重点讲了如果通过递归函数的返回值完成新加入节点和其父节点的赋值操作,并强调了搜索树的有序性。 +然后在递归中,我们重点讲了如何通过递归函数的返回值完成新加入节点和其父节点的赋值操作,并强调了搜索树的有序性。 最后依然给出了迭代的方法,迭代的方法就需要记录当前遍历节点的父节点了,这个和没有返回值的递归函数实现的代码逻辑是一样的。 From b93d9f6d89406cf2980cf94cfe313d7463d04d9e Mon Sep 17 00:00:00 2001 From: Yuhao Ju Date: Mon, 5 Dec 2022 10:19:20 +0800 Subject: [PATCH 43/56] =?UTF-8?q?update=200450.=E5=88=A0=E9=99=A4=E4=BA=8C?= =?UTF-8?q?=E5=8F=89=E6=90=9C=E7=B4=A2=E6=A0=91=E4=B8=AD=E7=9A=84=E8=8A=82?= =?UTF-8?q?=E7=82=B9:=20=E4=BF=AE=E6=94=B9=E9=94=99=E5=AD=97=EF=BC=8C?= =?UTF-8?q?=E4=BC=98=E5=8C=96=20go=20=E4=BB=A3=E7=A0=81=E9=A3=8E=E6=A0=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../0450.删除二叉搜索树中的节点.md | 42 +++++++++---------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/problems/0450.删除二叉搜索树中的节点.md b/problems/0450.删除二叉搜索树中的节点.md index d178596e..0b4048d5 100644 --- a/problems/0450.删除二叉搜索树中的节点.md +++ b/problems/0450.删除二叉搜索树中的节点.md @@ -25,7 +25,7 @@ # 思路 -搜索树的节点删除要比节点增加复杂的多,有很多情况需要考虑,做好心里准备。 +搜索树的节点删除要比节点增加复杂的多,有很多情况需要考虑,做好心理准备。 ## 递归 @@ -33,7 +33,7 @@ * 确定递归函数参数以及返回值 -说道递归函数的返回值,在[二叉树:搜索树中的插入操作](https://programmercarl.com/0701.二叉搜索树中的插入操作.html)中通过递归返回值来加入新节点, 这里也可以通过递归返回值删除节点。 +说到递归函数的返回值,在[二叉树:搜索树中的插入操作](https://programmercarl.com/0701.二叉搜索树中的插入操作.html)中通过递归返回值来加入新节点, 这里也可以通过递归返回值删除节点。 代码如下: @@ -66,7 +66,7 @@ if (root == nullptr) return root; ![450.删除二叉搜索树中的节点](https://tva1.sinaimg.cn/large/008eGmZEly1gnbj3k596mg30dq0aigyz.gif) -动画中棵二叉搜索树中,删除元素7, 那么删除节点(元素7)的左孩子就是5,删除节点(元素7)的右子树的最左面节点是元素8。 +动画中的二叉搜索树中,删除元素7, 那么删除节点(元素7)的左孩子就是5,删除节点(元素7)的右子树的最左面节点是元素8。 将删除节点(元素7)的左孩子放到删除节点(元素7)的右子树的最左面节点(元素8)的左孩子上,就是把5为根节点的子树移到了8的左孩子的位置。 @@ -251,7 +251,7 @@ public: **这里最关键的逻辑就是第五种情况(删除一个左右孩子都不为空的节点),这种情况一定要想清楚**。 -而且就算想清楚了,对应的代码也未必可以写出来,所以**这道题目即考察思维逻辑,也考察代码能力**。 +而且就算想清楚了,对应的代码也未必可以写出来,所以**这道题目既考察思维逻辑,也考察代码能力**。 递归中我给出了两种写法,推荐大家学会第一种(利用搜索树的特性)就可以了,第二种递归写法其实是比较绕的。 @@ -390,39 +390,39 @@ class Solution: ```Go // 递归版本 func deleteNode(root *TreeNode, key int) *TreeNode { - if root==nil{ + if root == nil { return nil } - if keyroot.Val{ - root.Right=deleteNode(root.Right,key) + if key > root.Val { + root.Right = deleteNode(root.Right, key) return root } - if root.Right==nil{ + if root.Right == nil { return root.Left } - if root.Left==nil{ + if root.Left == nil{ return root.Right } - minnode:=root.Right - for minnode.Left!=nil{ - minnode=minnode.Left + minnode := root.Right + for minnode.Left != nil { + minnode = minnode.Left } - root.Val=minnode.Val - root.Right=deleteNode1(root.Right) + root.Val = minnode.Val + root.Right = deleteNode1(root.Right) return root } -func deleteNode1(root *TreeNode)*TreeNode{ - if root.Left==nil{ - pRight:=root.Right - root.Right=nil +func deleteNode1(root *TreeNode)*TreeNode { + if root.Left == nil { + pRight := root.Right + root.Right = nil return pRight } - root.Left=deleteNode1(root.Left) + root.Left = deleteNode1(root.Left) return root } // 迭代版本 From 10302b0a143d0b0c736466da197c6dba8ff76c07 Mon Sep 17 00:00:00 2001 From: Yuhao Ju Date: Mon, 5 Dec 2022 14:33:48 +0800 Subject: [PATCH 44/56] =?UTF-8?q?update=200669.=E4=BF=AE=E5=89=AA=E4=BA=8C?= =?UTF-8?q?=E5=8F=89=E6=90=9C=E7=B4=A2=E6=A0=91:=20=E4=BC=98=E5=8C=96?= =?UTF-8?q?=E4=BB=A3=E7=A0=81=E9=A3=8E=E6=A0=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- problems/0669.修剪二叉搜索树.md | 56 +++++++++++++------------- 1 file changed, 28 insertions(+), 28 deletions(-) diff --git a/problems/0669.修剪二叉搜索树.md b/problems/0669.修剪二叉搜索树.md index 98af3c26..c2d7b79b 100644 --- a/problems/0669.修剪二叉搜索树.md +++ b/problems/0669.修剪二叉搜索树.md @@ -59,7 +59,7 @@ public: ![669.修剪二叉搜索树1](https://img-blog.csdnimg.cn/20210204155327203.png) -理解了最关键部分了我们在递归三部曲: +理解了最关键部分了我们再递归三部曲: * 确定递归函数的参数以及返回值 @@ -179,7 +179,7 @@ public: }; ``` -只看代码,其实不太好理解节点是符合移除的,这一块大家可以自己在模拟模拟! +只看代码,其实不太好理解节点是如何移除的,这一块大家可以自己再模拟模拟! ## 迭代法 @@ -301,19 +301,19 @@ class Solution: // 递归 func trimBST(root *TreeNode, low int, high int) *TreeNode { - if root==nil{ + if root == nil { return nil } - if root.Valhigh{//如果该节点的值大于最大值,则该节点更换为该节点的左节点值,继续遍历 - left:=trimBST(root.Left,low,high) + if root.Val > high { //如果该节点的值大于最大值,则该节点更换为该节点的左节点值,继续遍历 + left := trimBST(root.Left, low, high) return left } - root.Left=trimBST(root.Left,low,high) - root.Right=trimBST(root.Right,low,high) + root.Left = trimBST(root.Left, low, high) + root.Right = trimBST(root.Right, low, high) return root } @@ -323,25 +323,25 @@ func trimBST(root *TreeNode, low int, high int) *TreeNode { return nil } // 处理 root,让 root 移动到[low, high] 范围内,注意是左闭右闭 - for root != nil && (root.Valhigh){ - if root.Val < low{ + for root != nil && (root.Val < low || root.Val > high) { + if root.Val < low { root = root.Right - }else{ + } else { root = root.Left } } cur := root // 此时 root 已经在[low, high] 范围内,处理左孩子元素小于 low 的情况(左节点是一定小于 root.Val,因此天然小于 high) - for cur != nil{ - for cur.Left!=nil && cur.Left.Val < low{ + for cur != nil { + for cur.Left != nil && cur.Left.Val < low { cur.Left = cur.Left.Right } cur = cur.Left } cur = root // 此时 root 已经在[low, high] 范围内,处理右孩子大于 high 的情况 - for cur != nil{ - for cur.Right!=nil && cur.Right.Val > high{ + for cur != nil { + for cur.Right != nil && cur.Right.Val > high { cur.Right = cur.Right.Left } cur = cur.Right @@ -359,24 +359,24 @@ var trimBST = function(root, low, high) { if(root === null) { return null; } - while(root !==null &&(root.valhigh)) { - if(root.val high)) { + if(root.val < low) { root = root.right; }else { root = root.left; } } let cur = root; - while(cur!==null) { - while(cur.left&&cur.left.valhigh) { + while(cur !== null) { + while(cur.right && cur.right.val > high) { cur.right = cur.right.left; } cur = cur.right; @@ -391,16 +391,16 @@ var trimBST = function (root,low,high) { if(root === null) { return null; } - if(root.valhigh) { - let left = trimBST(root.left,low,high); + if(root.val > high) { + let left = trimBST(root.left, low, high); return left; } - root.left = trimBST(root.left,low,high); - root.right = trimBST(root.right,low,high); + root.left = trimBST(root.left, low, high); + root.right = trimBST(root.right, low, high); return root; } ``` From 57c41cd67076e7969e35a7aea353bac9931763e1 Mon Sep 17 00:00:00 2001 From: Yuhao Ju Date: Mon, 5 Dec 2022 15:39:02 +0800 Subject: [PATCH 45/56] =?UTF-8?q?update=200108.=E5=B0=86=E6=9C=89=E5=BA=8F?= =?UTF-8?q?=E6=95=B0=E7=BB=84=E8=BD=AC=E6=8D=A2=E4=B8=BA=E4=BA=8C=E5=8F=89?= =?UTF-8?q?=E6=90=9C=E7=B4=A2=E6=A0=91:=20=E4=BC=98=E5=8C=96go=20=E5=92=8C?= =?UTF-8?q?=20js=20=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...将有序数组转换为二叉搜索树.md | 47 ++++++++++--------- 1 file changed, 26 insertions(+), 21 deletions(-) diff --git a/problems/0108.将有序数组转换为二叉搜索树.md b/problems/0108.将有序数组转换为二叉搜索树.md index 9318a0e2..ffb60b38 100644 --- a/problems/0108.将有序数组转换为二叉搜索树.md +++ b/problems/0108.将有序数组转换为二叉搜索树.md @@ -35,7 +35,7 @@ 因为只要给我们一个有序数组,如果强调平衡,都可以以线性结构来构造二叉搜索树。 -例如 有序数组[-10,-3,0,5,9] 可以就可以构造成这样的二叉搜索树,如图。 +例如 有序数组[-10,-3,0,5,9] 就可以构造成这样的二叉搜索树,如图。 ![](https://code-thinking-1253855093.file.myqcloud.com/pics/20220930173553.png) @@ -147,7 +147,7 @@ public: }; ``` -**注意:在调用traversal的时候为什么传入的left和right为什么是0和nums.size() - 1,因为定义的区间为左闭右闭**。 +**注意:在调用traversal的时候传入的left和right为什么是0和nums.size() - 1,因为定义的区间为左闭右闭**。 ## 迭代法 @@ -354,10 +354,15 @@ class Solution: ```go func sortedArrayToBST(nums []int) *TreeNode { - if len(nums)==0{return nil}//终止条件,最后数组为空则可以返回 - root:=&TreeNode{nums[len(nums)/2],nil,nil}//按照BSL的特点,从中间构造节点 - root.Left=sortedArrayToBST(nums[:len(nums)/2])//数组的左边为左子树 - root.Right=sortedArrayToBST(nums[len(nums)/2+1:])//数字的右边为右子树 + if len(nums) == 0 { //终止条件,最后数组为空则可以返回 + return nil + } + idx := len(nums)/2 + root := &TreeNode{Val: nums[idx]} + + root.Left = sortedArrayToBST(nums[:idx]) + root.Right = sortedArrayToBST(nums[idx+1:]) + return root } ``` @@ -384,33 +389,33 @@ var sortedArrayToBST = function (nums) { 迭代 ```JavaScript var sortedArrayToBST = function(nums) { - if(nums.length===0){ + if(nums.length===0) { return null; } - let root=new TreeNode(0); //初始根节点 - let nodeQue=[root]; //放遍历的节点,并初始化 - let leftQue=[0]; //放左区间的下标,初始化 - let rightQue=[nums.length-1]; // 放右区间的下标 + let root = new TreeNode(0); //初始根节点 + let nodeQue = [root]; //放遍历的节点,并初始化 + let leftQue = [0]; //放左区间的下标,初始化 + let rightQue = [nums.length-1]; // 放右区间的下标 - while(nodeQue.length){ - let curNode=nodeQue.pop(); - let left=leftQue.pop(); - let right=rightQue.pop(); - let mid=left+Math.floor((right-left)/2); + while(nodeQue.length) { + let curNode = nodeQue.pop(); + let left = leftQue.pop(); + let right = rightQue.pop(); + let mid = left + Math.floor((right-left)/2); - curNode.val=nums[mid]; //将下标为mid的元素给中间节点 + curNode.val = nums[mid]; //将下标为mid的元素给中间节点 // 处理左区间 - if(left<=mid-1){ - curNode.left=new TreeNode(0); + if(left <= mid-1) { + curNode.left = new TreeNode(0); nodeQue.push(curNode.left); leftQue.push(left); rightQue.push(mid-1); } // 处理右区间 - if(right>=mid+1){ - curNode.right=new TreeNode(0); + if(right >= mid+1) { + curNode.right = new TreeNode(0); nodeQue.push(curNode.right); leftQue.push(mid+1); rightQue.push(right); From c03d5310a736f16accb2bf2e294743ac24e7d913 Mon Sep 17 00:00:00 2001 From: Yuhao Ju Date: Mon, 5 Dec 2022 19:13:43 +0800 Subject: [PATCH 46/56] =?UTF-8?q?update=200538.=E6=8A=8A=E4=BA=8C=E5=8F=89?= =?UTF-8?q?=E6=90=9C=E7=B4=A2=E6=A0=91=E8=BD=AC=E6=8D=A2=E4=B8=BA=E7=B4=AF?= =?UTF-8?q?=E5=8A=A0=E6=A0=91=EF=BC=9A=E6=9B=BF=E6=8D=A2=20go=20=E4=BB=A3?= =?UTF-8?q?=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...38.把二叉搜索树转换为累加树.md | 32 +++++++++---------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/problems/0538.把二叉搜索树转换为累加树.md b/problems/0538.把二叉搜索树转换为累加树.md index 823771b1..9940e604 100644 --- a/problems/0538.把二叉搜索树转换为累加树.md +++ b/problems/0538.把二叉搜索树转换为累加树.md @@ -45,11 +45,11 @@ # 思路 -一看到累加树,相信很多小伙伴都会疑惑:如何累加?遇到一个节点,然后在遍历其他节点累加?怎么一想这么麻烦呢。 +一看到累加树,相信很多小伙伴都会疑惑:如何累加?遇到一个节点,然后再遍历其他节点累加?怎么一想这么麻烦呢。 然后再发现这是一棵二叉搜索树,二叉搜索树啊,这是有序的啊。 -那么有序的元素如果求累加呢? +那么有序的元素如何求累加呢? **其实这就是一棵树,大家可能看起来有点别扭,换一个角度来看,这就是一个有序数组[2, 5, 13],求从后到前的累加数组,也就是[20, 18, 13],是不是感觉这就简单了。** @@ -233,23 +233,23 @@ class Solution: ## Go 弄一个sum暂存其和值 - ```go - //右中左 -func bstToGst(root *TreeNode) *TreeNode { - var sum int - RightMLeft(root,&sum) - return root -} -func RightMLeft(root *TreeNode,sum *int) *TreeNode { - if root==nil{return nil}//终止条件,遇到空节点就返回 - RightMLeft(root.Right,sum)//先遍历右边 - temp:=*sum//暂存总和值 - *sum+=root.Val//将总和值变更 - root.Val+=temp//更新节点值 - RightMLeft(root.Left,sum)//遍历左节点 +var pre int +func convertBST(root *TreeNode) *TreeNode { + pre = 0 + traversal(root) return root } + +func traversal(cur *TreeNode) { + if cur == nil { + return + } + traversal(cur.Right) + cur.Val += pre + pre = cur.Val + traversal(cur.Left) +} ``` ## JavaScript From 2575ff3b5c3dbc59f13cd469a785abaf4ad92325 Mon Sep 17 00:00:00 2001 From: Yuhao Ju Date: Wed, 7 Dec 2022 16:30:05 +0800 Subject: [PATCH 47/56] =?UTF-8?q?update=200235.=E4=BA=8C=E5=8F=89=E6=90=9C?= =?UTF-8?q?=E7=B4=A2=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=E4=BF=AE=E6=94=B9=E6=96=87=E5=AD=97?= =?UTF-8?q?=E6=95=B0=E6=8D=AE=E5=92=8C=E5=9B=BE=E7=89=87=E4=B8=8D=E5=AF=B9?= =?UTF-8?q?=E5=BA=94=E7=9A=84=E5=9C=B0=E6=96=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- problems/0235.二叉搜索树的最近公共祖先.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/problems/0235.二叉搜索树的最近公共祖先.md b/problems/0235.二叉搜索树的最近公共祖先.md index 391d1cfb..7f8f6422 100644 --- a/problems/0235.二叉搜索树的最近公共祖先.md +++ b/problems/0235.二叉搜索树的最近公共祖先.md @@ -60,12 +60,12 @@ 而递归遍历顺序,本题就不涉及到 前中后序了(这里没有中节点的处理逻辑,遍历顺序无所谓了)。 -如图所示:p为节点3,q为节点5 +如图所示:p为节点6,q为节点9 ![235.二叉搜索树的最近公共祖先2](https://code-thinking-1253855093.file.myqcloud.com/pics/20220926165141.png) -可以看出直接按照指定的方向,就可以找到节点4,为最近公共祖先,而且不需要遍历整棵树,找到结果直接返回! +可以看出直接按照指定的方向,就可以找到节点8,为最近公共祖先,而且不需要遍历整棵树,找到结果直接返回! ## 递归法 From 380fabb247985853a8b7fbe57bf2b340365ac5aa Mon Sep 17 00:00:00 2001 From: Yuhao Ju Date: Wed, 7 Dec 2022 20:05:34 +0800 Subject: [PATCH 48/56] =?UTF-8?q?update=200077.=E7=BB=84=E5=90=88=EF=BC=9A?= =?UTF-8?q?=E6=9B=B4=E6=96=B0python=20=E5=92=8C=20go=20=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- problems/0077.组合.md | 98 +++++++++++++++-------------------------- 1 file changed, 35 insertions(+), 63 deletions(-) diff --git a/problems/0077.组合.md b/problems/0077.组合.md index dabd2e8c..854b302b 100644 --- a/problems/0077.组合.md +++ b/problems/0077.组合.md @@ -34,7 +34,7 @@ # 思路 -本题这是回溯法的经典题目。 +本题是回溯法的经典题目。 直接的解法当然是使用for循环,例如示例中k为2,很容易想到 用两个for循环,这样就可以输出 和示例中一样的结果。 @@ -82,13 +82,13 @@ for (int i = 1; i <= n; i++) { 如果脑洞模拟回溯搜索的过程,绝对可以让人窒息,所以需要抽象图形结构来进一步理解。 -**我们在[关于回溯算法,你该了解这些!](https://programmercarl.com/回溯算法理论基础.html)中说道回溯法解决的问题都可以抽象为树形结构(N叉树),用树形结构来理解回溯就容易多了**。 +**我们在[关于回溯算法,你该了解这些!](https://programmercarl.com/回溯算法理论基础.html)中说到回溯法解决的问题都可以抽象为树形结构(N叉树),用树形结构来理解回溯就容易多了**。 那么我把组合问题抽象为如下树形结构: ![77.组合](https://img-blog.csdnimg.cn/20201123195223940.png) -可以看出这个棵树,一开始集合是 1,2,3,4, 从左向右取数,取过的数,不在重复取。 +可以看出这棵树,一开始集合是 1,2,3,4, 从左向右取数,取过的数,不再重复取。 第一次取1,集合变为2,3,4 ,因为k为2,我们只需要再取一个数就可以了,分别取2,3,4,得到集合[1,2] [1,3] [1,4],以此类推。 @@ -120,7 +120,7 @@ vector path; // 用来存放符合条件结果 其实不定义这两个全局变量也是可以的,把这两个变量放进递归函数的参数里,但函数里参数太多影响可读性,所以我定义全局变量了。 -函数里一定有两个参数,既然是集合n里面取k的数,那么n和k是两个int型的参数。 +函数里一定有两个参数,既然是集合n里面取k个数,那么n和k是两个int型的参数。 然后还需要一个参数,为int型变量startIndex,这个参数用来记录本层递归的中,集合从哪里开始遍历(集合就是[1,...,n] )。 @@ -389,9 +389,8 @@ class Solution(object): # 剪枝, 最后k - len(path)个节点直接构造结果,无需递归 last_startidx = n - (k - len(path)) + 1 - result.append(path + [idx for idx in range(last_startidx, n + 1)]) - for x in range(startidx, last_startidx): + for x in range(startidx, last_startidx + 1): path.append(x) backtracking(n, k, x + 1) # 递归 path.pop() # 回溯 @@ -435,6 +434,36 @@ class Solution: return res ``` +### Go +```Go +var ( + path []int + res [][]int +) + +func combine(n int, k int) [][]int { + path, res = make([]int, 0, k), make([][]int, 0) + dfs(n, k, 1) + return res +} + +func dfs(n int, k int, start int) { + if len(path) == k { // 说明已经满足了k个数的要求 + tmp := make([]int, k) + copy(tmp, path) + res = append(res, tmp) + return + } + for i := start; i <= n; i++ { // 从start开始,不往回走,避免出现重复组合 + if n - i + 1 < k - len(path) { // 剪枝 + break + } + path = append(path, i) + dfs(n, k, i+1) + path = path[:len(path)-1] + } +} +``` ### javascript @@ -481,63 +510,6 @@ function combine(n: number, k: number): number[][] { }; ``` - - -### Go -```Go -var res [][]int -func combine(n int, k int) [][]int { - res=[][]int{} - if n <= 0 || k <= 0 || k > n { - return res - } - backtrack(n, k, 1, []int{}) - return res -} -func backtrack(n,k,start int,track []int){ - if len(track)==k{ - temp:=make([]int,k) - copy(temp,track) - res=append(res,temp) - } - if len(track)+n-start+1 < k { - return - } - for i:=start;i<=n;i++{ - track=append(track,i) - backtrack(n,k,i+1,track) - track=track[:len(track)-1] - } -} -``` -剪枝: -```Go -var res [][]int -func combine(n int, k int) [][]int { - res=[][]int{} - if n <= 0 || k <= 0 || k > n { - return res - } - backtrack(n, k, 1, []int{}) - return res -} -func backtrack(n,k,start int,track []int){ - if len(track)==k{ - temp:=make([]int,k) - copy(temp,track) - res=append(res,temp) - } - if len(track)+n-start+1 < k { - return - } - for i:=start;i<=n;i++{ - track=append(track,i) - backtrack(n,k,i+1,track) - track=track[:len(track)-1] - } -} -``` - ### Rust ```Rust From 0cba0854d3533ada7847c7263811c9430f618264 Mon Sep 17 00:00:00 2001 From: Yuhao Ju Date: Wed, 7 Dec 2022 20:19:23 +0800 Subject: [PATCH 49/56] =?UTF-8?q?update=200077.=E7=BB=84=E5=90=88=E4=BC=98?= =?UTF-8?q?=E5=8C=96:=20=E6=9B=B4=E6=8D=A2=20go=20=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- problems/0077.组合优化.md | 40 +++++++++++++++++------------------ 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/problems/0077.组合优化.md b/problems/0077.组合优化.md index 91c7ce3b..34318d16 100644 --- a/problems/0077.组合优化.md +++ b/problems/0077.组合优化.md @@ -133,7 +133,7 @@ public: # 总结 -本篇我们准对求组合问题的回溯法代码做了剪枝优化,这个优化如果不画图的话,其实不好理解,也不好讲清楚。 +本篇我们针对求组合问题的回溯法代码做了剪枝优化,这个优化如果不画图的话,其实不好理解,也不好讲清楚。 所以我依然是把整个回溯过程抽象为一棵树形结构,然后可以直观的看出,剪枝究竟是剪的哪里。 @@ -194,28 +194,28 @@ class Solution: ``` Go: ```Go -var res [][]int +var ( + path []int + res [][]int +) + func combine(n int, k int) [][]int { - res=[][]int{} - if n <= 0 || k <= 0 || k > n { - return res - } - backtrack(n, k, 1, []int{}) - return res + path, res = make([]int, 0, k), make([][]int, 0) + dfs(n, k, 1) + return res } -func backtrack(n,k,start int,track []int){ - if len(track)==k{ - temp:=make([]int,k) - copy(temp,track) - res=append(res,temp) + +func dfs(n int, k int, start int) { + if len(path) == k { + tmp := make([]int, k) + copy(tmp, path) + res = append(res, tmp) + return } - if len(track)+n-start+1 < k { - return - } - for i:=start;i<=n;i++{ - track=append(track,i) - backtrack(n,k,i+1,track) - track=track[:len(track)-1] + for i := start; i <= n - (k-len(path)) + 1; i++ { + path = append(path, i) + dfs(n, k, i+1) + path = path[:len(path)-1] } } ``` From 77aeb31bad82702662be54ab77b7c640b6e30ca5 Mon Sep 17 00:00:00 2001 From: Yuhao Ju Date: Wed, 7 Dec 2022 21:07:21 +0800 Subject: [PATCH 50/56] =?UTF-8?q?update=200216.=E7=BB=84=E5=90=88=E6=80=BB?= =?UTF-8?q?=E5=92=8CIII:=20=E6=9B=BF=E6=8D=A2=20go=20=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- problems/0216.组合总和III.md | 41 +++++++++++++++++--------------- 1 file changed, 22 insertions(+), 19 deletions(-) diff --git a/problems/0216.组合总和III.md b/problems/0216.组合总和III.md index 9fc949cc..19fe1eb9 100644 --- a/problems/0216.组合总和III.md +++ b/problems/0216.组合总和III.md @@ -36,7 +36,7 @@ 想到这一点了,做过[77. 组合](https://programmercarl.com/0077.组合.html)之后,本题是简单一些了。 -本题k相当于了树的深度,9(因为整个集合就是9个数)就是树的宽度。 +本题k相当于树的深度,9(因为整个集合就是9个数)就是树的宽度。 例如 k = 2,n = 4的话,就是在集合[1,2,3,4,5,6,7,8,9]中求 k(个数) = 2, n(和) = 4的组合。 @@ -380,29 +380,32 @@ class Solution: 回溯+减枝 ```go +var ( + res [][]int + path []int +) func combinationSum3(k int, n int) [][]int { - var track []int// 遍历路径 - var result [][]int// 存放结果集 - backTree(n,k,1,&track,&result) - return result + res, path = make([][]int, 0), make([]int, 0, k) + dfs(k, n, 1, 0) + return res } -func backTree(n,k,startIndex int,track *[]int,result *[][]int){ - if len(*track)==k{ - var sum int - tmp:=make([]int,k) - for k,v:=range *track{ - sum+=v - tmp[k]=v - } - if sum==n{ - *result=append(*result,tmp) + +func dfs(k, n int, start int, sum int) { + if len(path) == k { + if sum == n { + tmp := make([]int, k) + copy(tmp, path) + res = append(res, tmp) } return } - for i:=startIndex;i<=9-(k-len(*track))+1;i++{//减枝(k-len(*track)表示还剩多少个可填充的元素) - *track=append(*track,i)//记录路径 - backTree(n,k,i+1,track,result)//递归 - *track=(*track)[:len(*track)-1]//回溯 + for i := start; i <= 9; i++ { + if sum + i > n || 9-i+1 < k-len(path) { + break + } + path = append(path, i) + dfs(k, n, i+1, sum+i) + path = path[:len(path)-1] } } ``` From c593fd5bbdae6c89dc046e7b926d7a6839cc098d Mon Sep 17 00:00:00 2001 From: Yuhao Ju Date: Wed, 7 Dec 2022 21:27:44 +0800 Subject: [PATCH 51/56] =?UTF-8?q?update=200017.=E7=94=B5=E8=AF=9D=E5=8F=B7?= =?UTF-8?q?=E7=A0=81=E7=9A=84=E5=AD=97=E6=AF=8D=E7=BB=84=E5=90=88:=20?= =?UTF-8?q?=E6=9B=B4=E6=96=B0=20go=20=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- problems/0017.电话号码的字母组合.md | 51 +++++++++----------- 1 file changed, 22 insertions(+), 29 deletions(-) diff --git a/problems/0017.电话号码的字母组合.md b/problems/0017.电话号码的字母组合.md index dd820a39..12a45a61 100644 --- a/problems/0017.电话号码的字母组合.md +++ b/problems/0017.电话号码的字母组合.md @@ -120,7 +120,7 @@ for (int i = 0; i < letters.size(); i++) { **注意这里for循环,可不像是在[回溯算法:求组合问题!](https://programmercarl.com/0077.组合.html)和[回溯算法:求组合总和!](https://programmercarl.com/0216.组合总和III.html)中从startIndex开始遍历的**。 -**因为本题每一个数字代表的是不同集合,也就是求不同集合之间的组合,而[77. 组合](https://programmercarl.com/0077.组合.html)和[216.组合总和III](https://programmercarl.com/0216.组合总和III.html)都是是求同一个集合中的组合!** +**因为本题每一个数字代表的是不同集合,也就是求不同集合之间的组合,而[77. 组合](https://programmercarl.com/0077.组合.html)和[216.组合总和III](https://programmercarl.com/0216.组合总和III.html)都是求同一个集合中的组合!** 注意:输入1 * #按键等等异常情况 @@ -356,38 +356,32 @@ class Solution: 主要在于递归中传递下一个数字 ```go +var ( + m []string + path []byte + res []string +) func letterCombinations(digits string) []string { - lenth:=len(digits) - if lenth==0 ||lenth>4{ - return nil + m = []string{"abc", "def", "ghi", "jkl", "mno", "pqrs", "tuv", "wxyz"} + path, res = make([]byte, 0), make([]string, 0) + if digits == "" { + return res } - digitsMap:= [10]string{ - "", // 0 - "", // 1 - "abc", // 2 - "def", // 3 - "ghi", // 4 - "jkl", // 5 - "mno", // 6 - "pqrs", // 7 - "tuv", // 8 - "wxyz", // 9 - } - res:=make([]string,0) - recursion("",digits,0,digitsMap,&res) - return res + dfs(digits, 0) + return res } -func recursion(tempString ,digits string, Index int,digitsMap [10]string, res *[]string) {//index表示第几个数字 - if len(tempString)==len(digits){//终止条件,字符串长度等于digits的长度 - *res=append(*res,tempString) +func dfs(digits string, start int) { + if len(path) == len(digits) { //终止条件,字符串长度等于digits的长度 + tmp := string(path) + res = append(res, tmp) return } - tmpK:=digits[Index]-'0' // 将index指向的数字转为int(确定下一个数字) - letter:=digitsMap[tmpK]// 取数字对应的字符集 - for i:=0;i Date: Thu, 8 Dec 2022 17:24:58 +0800 Subject: [PATCH 52/56] =?UTF-8?q?update=200039.=E7=BB=84=E5=90=88=E6=80=BB?= =?UTF-8?q?=E5=92=8C=EF=BC=9A=E4=BF=AE=E6=94=B9=E9=94=99=E5=AD=97=E5=92=8C?= =?UTF-8?q?=E6=9B=B4=E6=94=B9=20go=20=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- problems/0039.组合总和.md | 43 +++++++++++++++++------------------ 1 file changed, 21 insertions(+), 22 deletions(-) diff --git a/problems/0039.组合总和.md b/problems/0039.组合总和.md index 4e1df6c7..5244a1d6 100644 --- a/problems/0039.组合总和.md +++ b/problems/0039.组合总和.md @@ -42,7 +42,7 @@ candidates 中的数字可以无限制重复被选取。 题目中的**无限制重复被选取,吓得我赶紧想想 出现0 可咋办**,然后看到下面提示:1 <= candidates[i] <= 200,我就放心了。 -本题和[77.组合](https://programmercarl.com/0077.组合.html),[216.组合总和III](https://programmercarl.com/0216.组合总和III.html)和区别是:本题没有数量要求,可以无限重复,但是有总和的限制,所以间接的也是有个数的限制。 +本题和[77.组合](https://programmercarl.com/0077.组合.html),[216.组合总和III](https://programmercarl.com/0216.组合总和III.html)的区别是:本题没有数量要求,可以无限重复,但是有总和的限制,所以间接的也是有个数的限制。 本题搜索的过程抽象成树形结构如下: @@ -335,33 +335,32 @@ class Solution: 主要在于递归中传递下一个数字 ```go +var ( + res [][]int + path []int +) func combinationSum(candidates []int, target int) [][]int { - var trcak []int - var res [][]int - backtracking(0,0,target,candidates,trcak,&res) + res, path = make([][]int, 0), make([]int, 0, len(candidates)) + sort.Ints(candidates) // 排序,为剪枝做准备 + dfs(candidates, 0, target) return res } -func backtracking(startIndex,sum,target int,candidates,trcak []int,res *[][]int){ - //终止条件 - if sum==target{ - tmp:=make([]int,len(trcak)) - copy(tmp,trcak)//拷贝 - *res=append(*res,tmp)//放入结果集 + +func dfs(candidates []int, start int, target int) { + if target == 0 { // target 不断减小,如果为0说明达到了目标值 + tmp := make([]int, len(path)) + copy(tmp, path) + res = append(res, tmp) return } - if sum>target{return} - //回溯 - for i:=startIndex;i target { // 剪枝,提前返回 + break + } + path = append(path, candidates[i]) + dfs(candidates, i, target - candidates[i]) + path = path[:len(path) - 1] } - } ``` From 7284dffc429b87b75ceae98638cbc186544b28b1 Mon Sep 17 00:00:00 2001 From: Yuhao Ju Date: Thu, 8 Dec 2022 18:06:21 +0800 Subject: [PATCH 53/56] =?UTF-8?q?update=200040.=E7=BB=84=E5=90=88=E6=80=BB?= =?UTF-8?q?=E5=92=8CII:=20=E4=BF=AE=E6=94=B9=E9=94=99=E5=AD=97=EF=BC=8C?= =?UTF-8?q?=E6=9B=B4=E6=8D=A2=20go=20=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- problems/0040.组合总和II.md | 108 ++++++++++++++++---------------- 1 file changed, 53 insertions(+), 55 deletions(-) diff --git a/problems/0040.组合总和II.md b/problems/0040.组合总和II.md index fcfc396b..2d4b836a 100644 --- a/problems/0040.组合总和II.md +++ b/problems/0040.组合总和II.md @@ -110,13 +110,13 @@ if (sum == target) { } ``` -`sum > target` 这个条件其实可以省略,因为和在递归单层遍历的时候,会有剪枝的操作,下面会介绍到。 +`sum > target` 这个条件其实可以省略,因为在递归单层遍历的时候,会有剪枝的操作,下面会介绍到。 * **单层搜索的逻辑** 这里与[39.组合总和](https://programmercarl.com/0039.组合总和.html)最大的不同就是要去重了。 -前面我们提到:要去重的是“同一树层上的使用过”,如果判断同一树层上元素(相同的元素)是否使用过了呢。 +前面我们提到:要去重的是“同一树层上的使用过”,如何判断同一树层上元素(相同的元素)是否使用过了呢。 **如果`candidates[i] == candidates[i - 1]` 并且 `used[i - 1] == false`,就说明:前一个树枝,使用了candidates[i - 1],也就是说同一树层使用过candidates[i - 1]**。 @@ -438,76 +438,74 @@ class Solution: **使用used数组** ```go +var ( + res [][]int + path []int + used []bool +) func combinationSum2(candidates []int, target int) [][]int { - var trcak []int - var res [][]int - var history map[int]bool - history=make(map[int]bool) - sort.Ints(candidates) - backtracking(0,0,target,candidates,trcak,&res,history) + res, path = make([][]int, 0), make([]int, 0, len(candidates)) + used = make([]bool, len(candidates)) + sort.Ints(candidates) // 排序,为剪枝做准备 + dfs(candidates, 0, target) return res } -func backtracking(startIndex,sum,target int,candidates,trcak []int,res *[][]int,history map[int]bool){ - //终止条件 - if sum==target{ - tmp:=make([]int,len(trcak)) - copy(tmp,trcak)//拷贝 - *res=append(*res,tmp)//放入结果集 + +func dfs(candidates []int, start int, target int) { + if target == 0 { // target 不断减小,如果为0说明达到了目标值 + tmp := make([]int, len(path)) + copy(tmp, path) + res = append(res, tmp) return } - if sum>target{return} - //回溯 - // used[i - 1] == true,说明同一树枝candidates[i - 1]使用过 - // used[i - 1] == false,说明同一树层candidates[i - 1]使用过 - for i:=startIndex;i0&&candidates[i]==candidates[i-1]&&history[i-1]==false{ - continue + for i := start; i < len(candidates); i++ { + if candidates[i] > target { // 剪枝,提前返回 + break } - //更新路径集合和sum - trcak=append(trcak,candidates[i]) - sum+=candidates[i] - history[i]=true - //递归 - backtracking(i+1,sum,target,candidates,trcak,res,history) - //回溯 - trcak=trcak[:len(trcak)-1] - sum-=candidates[i] - history[i]=false + // used[i - 1] == true,说明同一树枝candidates[i - 1]使用过 + // used[i - 1] == false,说明同一树层candidates[i - 1]使用过 + if i > 0 && candidates[i] == candidates[i-1] && used[i-1] == false { + continue + } + path = append(path, candidates[i]) + used[i] = true + dfs(candidates, i+1, target - candidates[i]) + used[i] = false + path = path[:len(path) - 1] } } ``` **不使用used数组** ```go +var ( + res [][]int + path []int +) func combinationSum2(candidates []int, target int) [][]int { - var trcak []int - var res [][]int - sort.Ints(candidates) - backtracking(0,0,target,candidates,trcak,&res) + res, path = make([][]int, 0), make([]int, 0, len(candidates)) + sort.Ints(candidates) // 排序,为剪枝做准备 + dfs(candidates, 0, target) return res } -func backtracking(startIndex,sum,target int,candidates,trcak []int,res *[][]int){ - //终止条件 - if sum==target{ - tmp:=make([]int,len(trcak)) - //拷贝 - copy(tmp,trcak) - //放入结果集 - *res=append(*res,tmp) + +func dfs(candidates []int, start int, target int) { + if target == 0 { // target 不断减小,如果为0说明达到了目标值 + tmp := make([]int, len(path)) + copy(tmp, path) + res = append(res, tmp) return } - //回溯 - for i:=startIndex;istartIndex&&candidates[i]==candidates[i-1]{ - continue + for i := start; i < len(candidates); i++ { + if candidates[i] > target { // 剪枝,提前返回 + break } - //更新路径集合和sum - trcak=append(trcak,candidates[i]) - sum+=candidates[i] - backtracking(i+1,sum,target,candidates,trcak,res) - //回溯 - trcak=trcak[:len(trcak)-1] - sum-=candidates[i] + // i != start 限制了这不对深度遍历到达的此值去重 + if i != start && candidates[i] == candidates[i-1] { // 去重 + continue + } + path = append(path, candidates[i]) + dfs(candidates, i+1, target - candidates[i]) + path = path[:len(path) - 1] } } ``` From 40ce44dd44f4c0396b99f5310753336fbddaeb06 Mon Sep 17 00:00:00 2001 From: Yuhao Ju Date: Thu, 8 Dec 2022 21:07:03 +0800 Subject: [PATCH 54/56] =?UTF-8?q?update=200131.=E5=88=86=E5=89=B2=E5=9B=9E?= =?UTF-8?q?=E6=96=87=E4=B8=B2:=20=E4=BF=AE=E6=94=B9=E9=94=99=E5=AD=97?= =?UTF-8?q?=EF=BC=8C=E6=9B=BF=E6=8D=A2=20go=20=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- problems/0131.分割回文串.md | 64 +++++++++++++++----------------- 1 file changed, 29 insertions(+), 35 deletions(-) diff --git a/problems/0131.分割回文串.md b/problems/0131.分割回文串.md index 3a3c2d73..0081223c 100644 --- a/problems/0131.分割回文串.md +++ b/problems/0131.分割回文串.md @@ -43,8 +43,8 @@ 例如对于字符串abcdef: -* 组合问题:选取一个a之后,在bcdef中再去选取第二个,选取b之后在cdef中在选组第三个.....。 -* 切割问题:切割一个a之后,在bcdef中再去切割第二段,切割b之后在cdef中在切割第三段.....。 +* 组合问题:选取一个a之后,在bcdef中再去选取第二个,选取b之后在cdef中再选取第三个.....。 +* 切割问题:切割一个a之后,在bcdef中再去切割第二段,切割b之后在cdef中再切割第三段.....。 感受出来了不? @@ -78,7 +78,7 @@ void backtracking (const string& s, int startIndex) { ![131.分割回文串](https://code-thinking.cdn.bcebos.com/pics/131.%E5%88%86%E5%89%B2%E5%9B%9E%E6%96%87%E4%B8%B2.jpg) -从树形结构的图中可以看出:切割线切到了字符串最后面,说明找到了一种切割方法,此时就是本层递归的终止终止条件。 +从树形结构的图中可以看出:切割线切到了字符串最后面,说明找到了一种切割方法,此时就是本层递归的终止条件。 **那么在代码里什么是切割线呢?** @@ -98,7 +98,7 @@ void backtracking (const string& s, int startIndex) { * 单层搜索的逻辑 -**来看看在递归循环,中如何截取子串呢?** +**来看看在递归循环中如何截取子串呢?** 在`for (int i = startIndex; i < s.size(); i++)`循环中,我们 定义了起始位置startIndex,那么 [startIndex, i] 就是要截取的子串。 @@ -126,7 +126,7 @@ for (int i = startIndex; i < s.size(); i++) { 最后我们看一下回文子串要如何判断了,判断一个字符串是否是回文。 -可以使用双指针法,一个指针从前向后,一个指针从后先前,如果前后指针所指向的元素是相等的,就是回文字符串了。 +可以使用双指针法,一个指针从前向后,一个指针从后向前,如果前后指针所指向的元素是相等的,就是回文字符串了。 那么判断回文的C++代码如下: @@ -295,7 +295,7 @@ public: 除了这些难点,**本题还有细节,例如:切割过的地方不能重复切割所以递归函数需要传入i + 1**。 -所以本题应该是一个道hard题目了。 +所以本题应该是一道hard题目了。 **可能刷过这道题目的录友都没感受到自己原来克服了这么多难点,就把这道题目AC了**,这应该叫做无招胜有招,人码合一,哈哈哈。 @@ -432,45 +432,39 @@ class Solution: ``` ## Go -**注意切片(go切片是披着值类型外衣的引用类型)** ```go +var ( + path []string // 放已经回文的子串 + res [][]string +) func partition(s string) [][]string { - var tmpString []string//切割字符串集合 - var res [][]string//结果集合 - backTracking(s,tmpString,0,&res) + path, res = make([]string, 0), make([][]string, 0) + dfs(s, 0) return res } -func backTracking(s string,tmpString []string,startIndex int,res *[][]string){ - if startIndex==len(s){//到达字符串末尾了 - //进行一次切片拷贝,怕之后的操作影响tmpString切片内的值 - t := make([]string, len(tmpString)) - copy(t, tmpString) - *res=append(*res,t) + +func dfs(s string, start int) { + if start == len(s) { // 如果起始位置等于s的大小,说明已经找到了一组分割方案了 + tmp := make([]string, len(path)) + copy(tmp, path) + res = append(res, tmp) + return } - for i:=startIndex;i Date: Thu, 8 Dec 2022 21:14:57 +0800 Subject: [PATCH 55/56] =?UTF-8?q?update=200093.=E5=A4=8D=E5=8E=9FIP?= =?UTF-8?q?=E5=9C=B0=E5=9D=80:=20=E6=9B=BF=E6=8D=A2=20go=20=E4=BB=A3?= =?UTF-8?q?=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- problems/0093.复原IP地址.md | 78 +++++++++++++++------------------ 1 file changed, 36 insertions(+), 42 deletions(-) diff --git a/problems/0093.复原IP地址.md b/problems/0093.复原IP地址.md index ce62cac1..97178cd5 100644 --- a/problems/0093.复原IP地址.md +++ b/problems/0093.复原IP地址.md @@ -424,6 +424,42 @@ class Solution: return True ``` +## Go + +```go +var ( + path []string + res []string +) +func restoreIpAddresses(s string) []string { + path, res = make([]string, 0, len(s)), make([]string, 0) + dfs(s, 0) + return res +} +func dfs(s string, start int) { + if len(path) == 4 { // 够四段后就不再继续往下递归 + if start == len(s) { + str := strings.Join(path, ".") + res = append(res, str) + } + return + } + for i := start; i < len(s); i++ { + if i != start && s[start] == '0' { // 含有前导 0,无效 + break + } + str := s[start : i+1] + num, _ := strconv.Atoi(str) + if num >= 0 && num <= 255 { + path = append(path, str) // 符合条件的就进入下一层 + dfs(s, i+1) + path = path[:len(path) - 1] + } else { // 如果不满足条件,再往后也不可能满足条件,直接退出 + break + } + } +} +``` ## JavaScript @@ -494,48 +530,6 @@ function restoreIpAddresses(s: string): string[] { }; ``` -## Go - -回溯(对于前导 0的IP(特别注意s[startIndex]=='0'的判断,不应该写成s[startIndex]==0,因为s截取出来不是数字)) - -```go -func restoreIpAddresses(s string) []string { - var res,path []string - backTracking(s,path,0,&res) - return res -} -func backTracking(s string,path []string,startIndex int,res *[]string){ - //终止条件 - if startIndex==len(s)&&len(path)==4{ - tmpIpString:=path[0]+"."+path[1]+"."+path[2]+"."+path[3] - *res=append(*res,tmpIpString) - } - for i:=startIndex;i1&&s[startIndex]=='0'{//对于前导 0的IP(特别注意s[startIndex]=='0'的判断,不应该写成s[startIndex]==0,因为s截取出来不是数字) - return false - } - if checkInt>255{ - return false - } - return true -} - -``` - ## Rust ```Rust From 74ccecbdcd80d7c2ca9107e73ff65d5a35e352d7 Mon Sep 17 00:00:00 2001 From: Yuhao Ju Date: Thu, 8 Dec 2022 21:30:41 +0800 Subject: [PATCH 56/56] =?UTF-8?q?update=200078.=E5=AD=90=E9=9B=86:=20?= =?UTF-8?q?=E6=9B=BF=E6=8D=A2=20go=20=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- problems/0078.子集.md | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/problems/0078.子集.md b/problems/0078.子集.md index e271a96f..b5958e65 100644 --- a/problems/0078.子集.md +++ b/problems/0078.子集.md @@ -227,25 +227,25 @@ class Solution: ## Go ```Go -var res [][]int -func subset(nums []int) [][]int { - res = make([][]int, 0) - sort.Ints(nums) - Dfs([]int{}, nums, 0) - return res +var ( + path []int + res [][]int +) +func subsets(nums []int) [][]int { + res, path = make([][]int, 0), make([]int, 0, len(nums)) + dfs(nums, 0) + return res } -func Dfs(temp, nums []int, start int){ - tmp := make([]int, len(temp)) - copy(tmp, temp) - res = append(res, tmp) - for i := start; i < len(nums); i++{ - //if i>start&&nums[i]==nums[i-1]{ - // continue - //} - temp = append(temp, nums[i]) - Dfs(temp, nums, i+1) - temp = temp[:len(temp)-1] - } +func dfs(nums []int, start int) { + tmp := make([]int, len(path)) + copy(tmp, path) + res = append(res, tmp) + + for i := start; i < len(nums); i++ { + path = append(path, nums[i]) + dfs(nums, i+1) + path = path[:len(path)-1] + } } ```