文章目录
- [39 组合总和](https://programmercarl.com/0039.%E7%BB%84%E5%90%88%E6%80%BB%E5%92%8C.html#%E7%AE%97%E6%B3%95%E5%85%AC%E5%BC%80%E8%AF%BE)
- [40 组合总和Ⅱ](https://programmercarl.com/0040.%E7%BB%84%E5%90%88%E6%80%BB%E5%92%8CII.html#%E6%80%9D%E8%B7%AF)
- [131 回文串的切割](https://programmercarl.com/0131.%E5%88%86%E5%89%B2%E5%9B%9E%E6%96%87%E4%B8%B2.html#%E6%80%9D%E8%B7%AF)
39 组合总和
- candidates无重复,其中数字可以无限制的重复选取。
- 由于可以选取,递归的时候就不是从 i+1 开始,而是从 i 开始的(重复的含义,最大的不同)。
- 回溯三部曲:
- 参数和返回值: candidates提供基础数据,target表示path中的数据中和,startIndex表示当层的开始,提供树的纵向遍历。
- 结束条件:
if (target == 0) {
result.push_back(path);
return;
- 单层逻辑
for(int i = startIndex; i<candidates.size() && target - candidates[i] >= 0; i++){
path.push_back(candidates[i]);
target -= candidates[i];
backtracking(candidates, target, i);
path.pop_back();
target += candidates[i];
}
40 组合总和Ⅱ
- candidates是有重复的,最后的组合是无重复的。
- 去除重复的元素:
- 同一层的重复元素;
- 同一树枝的重复元素;
- 根据本题的要求,由于不能解集不能包括重复的集合,所以同一层如果未加入组合的数和已加入组合的数出现重复,需要跳过不处理,否则将导致同一层出现两个相同的元素,最后有相同的组合。
- 为便于找集合外和集合内的,排序后使用candidates[i] == candadates[i-1]即可,排序用快排的sort(candidates.begin(), candidates.end())实现。
- candidates[i] == candidates[i-1]只能说明candidates中有重复的元素,不能说明两者是否在同一层,有可能是同一树枝,则这是满足要求的。两种方法说明两个相同元素是不是在同一层:一是vector<bool> used实现,如果used[i-1]=false;说明当前值是前一个的回溯,两个在同一层,continue,如果used[i-1]=true;说明当前值是前一个的同一树枝,继续执行。二是比较startIndex和i的大小,如果 i > startIndex 则说明同一层,continue。
- 回溯三部曲:
- 返回值和参数:参数candidates提供基础数据、target提供path中数据的和、startIndex提供应该从candidates的哪个开始,形成树的纵向遍历。
- 终止条件:遇到path中的和等于target
if(target == 0){
result.push_back(path);
return;
}
- 单层逻辑
used数组
for(int i = startIndex; i < candidates.size() && target - candidates[i] >= 0; i++){
//与39不同的地方,需要处理是否树的当层重复
if(i > 0 && candidates[i] == candidates[i-1] && used[i-1] == false) continue;
used[i] = true;//
path.push_back(candidates[i]);
target -= candidates[i];
backtracking(candidates, target, i+1);
used[i] = false;//回溯
path.pop_back();
target += candidates[i];
}
startIndex与i的比较
for(int i = startIndex; i < candidates.size() && target - candidates[i] >= 0; i++){
//与39不同的地方,需要处理是否树的当层重复
if(i > 0 && candidates[i] == candidates[i-1] && i > startIndex) continue;
path.push_back(candidates[i]);
target -= candidates[i];
backtracking(candidates, target, i+1);
path.pop_back();//回溯
target += candidates[i];
}
131 回文串的切割
切割问题转为组合问题
- 切割用切割线表示,树形结构与组合的树形结构的值不同。
- 如何收集切割的过程值vecctor<string> path收集。
- 如何把判断回文的逻辑放入到单层逻辑, bool isParlindromes(string s, int begin, int end){}。
- 如何表示切割的字串,字串的产生是在for(int i = startIndex; i<s.size(); i++){ [startIndex, i]; }。
回溯三部曲:
5. 参数与返回值:字符串s和在s中开始的位置startIndex。
6. 终止条件:切割的切割线到了最后一个字符的后面:aab|。
if (startIndex >= s.size()){
result.push_back(path);
return;
}
- 单层逻辑
- 切割字符串s得到字串。
- 判读是否是回文串的逻辑。
bool isParlindrome(string s, int begin, int end){
while(begin <= end) {
if(s[begin] != s[end]) return false;
}
return true;
}
for(int i = startIndex; i< s.size(); i++){//横向遍历
if(isParlindrome(s, startIndex, i)){//判断是回文串
string str = s.substr(startIndex, i - startIndex + 1);
path.push_back(str);
}
else{ continue; }
backtracking(s, i+1);//纵向遍历,切割下一个
path.pop_back();
}