39.组合总和
题目链接https://leetcode.cn/problems/combination-sum
自己做的时候在for循环里面循环条件用的是
for(int i=0;i<candidates.size();i++)
发现有重复的元素,在报错,这道题是要数组里元素的和加起来等于target,因为是组合问题,排列是没有顺序的区别的,也就是说不能走回头路,我赋值i=0,那在每一次递归的时候都会从第一个元素开始选,那么比如我上次选的1,2 这次就会选到2,1就肯定会有重复的数组了,所以这里从startindex开始选的话,我每次就都从这个数往后面选,就可以进行正确的递归了
class Solution {
public:
vector<int> path;
vector<vector<int>> result;
void backtracking(vector<int>&candidates,int target,int sum,int startindex){
if(sum>target)return;
if(sum==target){
result.push_back(path);
return;
}
for(int i=startindex;i<candidates.size();i++){
path.push_back(candidates[i]);
sum+=candidates[i];
backtracking(candidates,target,sum,i);
sum-=candidates[i];
path.pop_back();
}
}
vector<vector<int>> combinationSum(vector<int>& candidates, int target) {
backtracking(candidates,target,0,0);
return result;
}
};
40.组合总和||
题目链接https://leetcode.cn/problems/combination-sum-ii
这块代码随想录讲得真的牛,建议直接看视频
这里代码随想录提出了树枝去重和树层去重,就是这道题,求的组合既要有重复元素,又不能有重复的组合,所以在选的过程里面可以定义一个bool类型的used数组,在竖直方向上的选取是可以重复的,比如
andidates = [1,1,2,3,4], target = 5
我的组合是可以包含有[1,1,3]的,这叫树枝去重
然后假设我第一个1取到的组合[1,4]
那我第二个1肯定也能取到组合[1,4]这样不行,就必须要把这个数过掉,这叫树层去重
也就是我们相同的元素在一个组合里:√
相同元素在不同组合选到了同几个数:×
所以我们定义的used数组就派上了用场,只要有两个相同的数且前一个相同的数没有用过,也就是我们不在一个组合里了,那直接continue吧,就自动把这个数过掉了,代码体现是这个:
if (i>0&&used[i - 1] == 0 && candidates[i] == candidates[i - 1]) {
continue;}
class Solution {
public:
vector<int> path;
vector<vector<int>> result;
void backtracking(vector<int>& candidates, int target, int sum,
int startindex, vector<bool>& used) {
if (sum == target) {
result.push_back(path);
return;
}
for (int i = startindex;
i < candidates.size() && sum + candidates[i] <= target; i++) {
//在循环里面做剪枝,可以少做一次循环
if (i>0&&used[i - 1] == 0 && candidates[i] == candidates[i - 1]) {
continue;
}
sum += candidates[i];
path.push_back(candidates[i]);
used[i] = true;
backtracking(candidates, target, sum, i + 1, used);
path.pop_back();
used[i] = false;
sum -= candidates[i];
}
}
vector<vector<int>> combinationSum2(vector<int>& candidates, int target) {
sort(candidates.begin(), candidates.end());
//排序,让相同元素挨在一起,在后面好进行树层去重
vector<bool> used(candidates.size(), false);
backtracking(candidates, target, 0, 0, used);
return result;
}
};
131.分割回文串
题目链接https://leetcode.cn/problems/palindrome-partitioning
看这道题的第一印象是我累个乖乖这咋写!??
这道题的思路就是用i和startindex来进行选取子串,因为startindex指向的是传入的第一个数,也就是切割起点,而我的i是可以不断变化的i<s.size()的,所以i就是切割的终点,所以我我只需要判断一下我这个(startindex,i)这个区间里面是不是回文串,只要是回文串我就把他切割下来放到我的path里面,不是的话就回去切割下一个字符。
到最后只要我的startindex都等于数组的最后一个字符后了,那就肯定截止了,往result里面塞就行,这里终止条件没有进行筛选是因为在循环的时候就已经进行剪枝了,你放在path数组里的肯定都是回文串了,那我直接收集你的结果就行。
class Solution {
public:
vector<string> path;
vector<vector<string>> result;
bool Palindrome(string& str, int start, int end) {//判断回文串
for (int i = start, j = end; i < j; i++, j--) {
if (str[i] != str[j]) {
return false;
}
}
return true;
}
void backtracking(string& s, int startindex) {
if (startindex == s.size()) {//单次递归终止条件
result.push_back(path);
return;
}
for (int i = startindex; i < s.size(); i++) {
if (Palindrome(s, startindex, i)) {//如果是回文串
string str = s.substr(startindex, i - startindex + 1);
path.push_back(str);//就把这个串先放到path里面
} else
continue;
backtracking(s, i + 1);
path.pop_back();
}
}
vector<vector<string>> partition(string s) {
backtracking(s, 0);
return result;
}
};