心得体会:
最开始的准备自然是把需要的准备切片或者数组创建好
其次就是确定好回溯算法入口,就像递归一样确定好递归的入口在哪
进行回溯算法的主体构建的时候一定要对回溯的过程先进行构建,在脑海中有一定的思路
自然的思路肯定是在在dfs后进入第一个循环,举例先进入dfs(0),我们要明确在dfs(0)中
我们已经确定好的其他局部变量的值,把第一个符合的答案加入到path切片中,
接着进入dfs(变量+1),再把符合的答案加入到path切片中去,不断的向内递
接着我们要确定一个临界条件,就像递归一样,我们来到了归的过程
和递归不一样的是,在回溯的归的过程中,我们的每一个归都会有一个或者多个的向内再去寻找答案或者是递的过程,而递归的归的过程可能就是执行一个动作,回溯的归的过程执行的动作更多,所以我们要在回溯的归的过程中严谨好每个局部变量的值,这一点对于回溯的过程至关重要
在多次的回溯后我们就能找到所有需要的答案
以子集这个题目进行说明:
给你一个整数数组 nums
,数组中的元素 互不相同 。返回该数组所有可能的
子集
(幂集)。
解集 不能 包含重复的子集。你可以按 任意顺序 返回解集。
示例 1:
输入:nums = [1,2,3] 输出:[[],[1],[2],[1,2],[3],[1,3],[2,3],[1,2,3]]
示例 2:
输入:nums = [0] 输出:[[],[0]]
示例代码:
func subsets(nums []int) [][]int {
n := len(nums)
ans := make([][]int, 0, 1<<n) // 预分配空间
path := make([]int, 0, n) // 预分配空间
var dfs func(int)
dfs = func(i int) {
ans = append(ans, slices.Clone(path)) // 复制 path
if i == n {
return
}
for j := i; j < n; j++ { // 枚举选择的数字
path = append(path, nums[j])
dfs(j + 1)
path = path[:len(path)-1] // 恢复现场
}
}
dfs(0)
return ans
}
题目需要的是我们找到所有的子集,我们以123为例
所以我们需要首先确定我们从第一个数字进行存储,我们首先从dfs(0)进入,回溯在归的过程中找多个答案,所以我们在回溯的函数中我们要创建一个循环,首先把第一个数字放入path,接着进入dfs(1)再放入第二个数字,直到我们把所有的数字一次性放进入后,我们来到的临界条件的判定,
我们就要进入归的过程,删除最后一个数字,删完之后我们的循环没办法继续执行,因为此时的j已经等于2,当j=3时循环无法执行
我们跳回dfs(1),dfs(1)之后紧接着的就是path的清除,此时在dfs(1)中我们的j=1,进行完path的删除后,循环继续,j=2,我们把3放入path,接下来的就都是一样的操作,理解回溯