From fded0906dd3c193521355bd7c69c573a674c5562 Mon Sep 17 00:00:00 2001 From: Yuhao Ju Date: Thu, 8 Dec 2022 17:24:58 +0800 Subject: [PATCH 1/5] =?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 2/5] =?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 3/5] =?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 4/5] =?UTF-8?q?update=200093.=E5=A4=8D=E5=8E=9FIP=E5=9C=B0?= =?UTF-8?q?=E5=9D=80:=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/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 5/5] =?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] + } } ```