39. 组合总和
文章讲解:代码随想录
视频讲解:带你学透回溯算法-组合总和(对应「leetcode」力扣题目:39.组合总和)| 回溯法精讲!_哔哩哔哩_bilibili
思路:
输入:candidates = [2,3,6,7], target = 7 输出:[[2,2,3],[7]]
定义两个全局变量,二维数组result存放结果集,数组path存放符合条件的结果。
1.递归函数参数
首先是题目中给出的参数,集合candidates, 和目标值target。
此外还定义了int型的sum变量来统计单一结果path里的总和
还需要startIndex来控制for循环的起始位置
2.回溯函数终止条件
终止只有两种情况,sum大于target直接返回;sum等于target的时候,需要收集结果
3.单层搜索的过程
单层for循环依然是从startIndex开始,搜索candidates集合。
剪枝:
对总集合排序之后,如果下一层的sum(就是本层的 sum + candidates[i])已经大于target,就可以结束本轮for循环的遍历。
时间复杂度: O(n * 2^n),空间复杂度: O(target)
40.组合总和II
题目链接:40. 组合总和 II - 力扣(LeetCode)
文章讲解:代码随想录
视频讲解:回溯算法中的去重,树层去重树枝去重,你弄清楚了没?| LeetCode:40.组合总和II_哔哩哔哩_bilibili
思路:输入: candidates = [2,5,2,1,2], target = 5, 输出:[[1,2,2],[5]]
1.递归函数参数
集合candidates, 和目标值target,int型的sum变量来统计单一结果path里的总和,startIndex来控制for循环的起始位置,还需要加一个bool型数组visit,用来记录同一树枝上的元素是否使用过(去重也是visit完成)
2.回溯函数终止条件
终止只有两种情况,sum大于target直接返回;sum等于target的时候,需要收集结果
3.单层搜索的过程
如果candidates[i] == candidates[i - 1] 并且 used[i - 1] == false,就说明:前一个树枝,使用了candidates[i - 1],也就是说同一树层使用过candidates[i - 1],for循环里就应该做continue的操作。
used[i - 1] == true,说明同一树枝candidates[i - 1]使用过;说明是进入下一层递归,去下一个数,所以是树枝上;
used[i - 1] == false,说明同一树层candidates[i - 1]使用过;因为同一树层,当前取的 candidates[i] 是从 candidates[i - 1] 回溯而来的。
上
时间复杂度: O(n * 2^n),空间复杂度: O(n)
131.分割回文串
题目链接:131. 分割回文串 - 力扣(LeetCode)
文章讲解:代码随想录
视频讲解:带你学透回溯算法-分割回文串(对应力扣题目:131.分割回文串)| 回溯法精讲!_哔哩哔哩_bilibili
思路:
切割问题类似组合问题,例如对于字符串abcdef:
组合问题:选取一个a之后,在bcdef中再去选取第二个,选取b之后在cdef中再选取第三个.....
切割问题:切割一个a之后,在bcdef中再去切割第二段,切割b之后在cdef中再切割第三段.....
递归用来纵向遍历,for循环用来横向遍历,切割线(就是图中的红线)切割到字符串的结尾位置,说明找到了一个切割方法
1.递归函数参数
全局变量数组path存放切割后回文的子串,二维数组result存放结果集
还需要startIndex,因为切割过的地方,不能重复切割,和组合问题也是保持一致
2.回溯函数终止条件
从树形结构的图中可以看出:切割线切到了字符串最后面,说明找到了一种切割方法,此时就是本层递归的终止条件;
在处理组合问题的时候,递归参数需要传入startIndex,表示下一轮递归遍历的起始位置,这个startIndex就是切割线。
3.单层搜索的过程
在for (int i = startIndex; i < s.size(); i++)循环中,我们 定义了起始位置startIndex,那么 [startIndex, i] 就是要截取的子串。
首先判断这个子串是不是回文,如果是回文,就加入在vector<string> path中,path用来记录切割过的回文子串。
切割过的位置,不能重复切割,所以,backtracking(s, i + 1); 传入下一层的起始位置为i + 1
时间复杂度: O(n * 2^n),空间复杂度: O(n^2)