回溯2
切割问题:是在每个节点判断是否是要剪枝收割元素。 startidx 是切割起点,i是本次切割终点
分割回文串
复原ip地址
非递减子序列
都是在树的节点依照题意判断,之后决定是否剪枝。
也就是都有if判断来剪枝 。
下面是非递减子序列。
下面是回文串
下面是复原ip地址
子集问题: 与组合问题的区别是在每个节点上收割结果 。
子集
子集去重:主要是树层去重。 判断条件是
if(used[i-1] == 0 && i> 0 && nums[i] == nums[i-1] )
[子集2] (https://leetcode.cn/problems/subsets-ii/description/)
组合问题
在每个节点收割元素 。 记住startidx 在每次递归时 要加1 。 这相当于for循环的i++ ;
这种回溯递归就是暴力枚举 。 不过是把代码简化了,并且把问题抽象为树。
组合总和
涉及到去重。 一般是树层元素去重。 树枝不去重。
如果发现重复的元素。直接剪枝(continue掉这次for循环)
if( i >0 && candidates[i-1] == candidates[i] && 0 ==used[i-1] ){continue ; }
used[i-1] =0 确保这是在处理同一树层的元素。 因为used[i-1] = 1 的话表示处理的是树枝元素, 是从上一个树枝元素递归过来的元素。
组合总和II
排列问题:与组合问题不同的是,组合是同一个的组合,可能是不同的排列.要使用used数组,表示在本次树枝的遍历使用过的元素,使用过的就不使用了。 另外每次树枝都是从i==0 开始遍历。
全排列
void backtracking(vector<int>& nums , int k ){if(path.size() == k) // 递归边界 {res.push_back(path) ;return ; }if(path.size() > k){return ; }for(int i = 0 ; i< nums.size(); ++ i){if( used[i] == 0 ){path.push_back(nums[i]) ;used[i] = 1 ; backtracking(nums, k ) ; used[i] = 0 ; path.pop_back() ; }}}
全排列去重也和组合去重一样都是把树层的元素 去重,通过剪枝去重
if(i>0 && nums[i-1] == nums[i] && used[i-1] == 0 ){continue ; }
[全排列2](https://leetcode.cn/problems/permutations-ii/description/)