39. 组合总和
开始的想法是遍历所有的元素,但是这样会导致重复(例如[2,3,3]和[3,2,3]),不出意外地爆栈了。
class Solution {
public:
vector<int> path;
vector<vector<int>> res;
void backtrace(vector<int>& candidates, int target, int sum, int startID) {
if(sum == target) {
res.push_back(path);
return;
}
for(int i = 0; i < candidates.size();++i) {
sum += candidates[i];
path.push_back(candidates[i]);
backtrace(candidates,target,sum);
path.pop_back();
sum -= candidates[i];
}
}
vector<vector<int>> combinationSum(vector<int>& candidates, int target) {
backtrace(candidates,target,0);
return res;
}
};
优化后:
加入了排序+剪枝后能通过测试。
class Solution {
public:
vector<int> path;
vector<vector<int>> res;
void backtrace(vector<int>& candidates, int target, int startID) {
if(0 == target) {
res.push_back(path);
return;
}
for(int i = startID; i < candidates.size();++i) {
//剪枝,因为之前排序过,更大的元素都不符合条件了
if(target < candidates[i]) break;
target -= candidates[i];
path.push_back(candidates[i]);
backtrace(candidates,target,i);
path.pop_back();
target += candidates[i];
}
}
vector<vector<int>> combinationSum(vector<int>& candidates, int target) {
sort(candidates.begin(),candidates.end());
backtrace(candidates,target,0);
return res;
}
};
40.组合总和II
此题的要求是可以使用重复的元素但不能选用重复的组合。我们设置一个数组来表示对应元素是否之前被使用过。如果false,说明不是重复选择该元素,跳过该情况;如果true,说明重复选择该元素,考虑该情况。
class Solution {
public:
vector<int> path;
vector<vector<int>> res;
void backtrace(vector<int>& candidates, int target, int startID,vector<bool> &repeated) {
if(0 == target) {
res.push_back(path);
return;
}
for(int i = startID; i < candidates.size();++i) {
if(target < candidates[i]) break;
if(i > 0 && candidates[i]==candidates[i-1] && repeated[i - 1] == false) {
continue;
}
target -= candidates[i];
repeated[i] = true;
path.push_back(candidates[i]);
backtrace(candidates,target,i+1,repeated);
path.pop_back();
repeated[i] = false;
target += candidates[i];
}
}
vector<vector<int>> combinationSum2(vector<int>& candidates, int target) {
vector<bool> repeated(candidates.size(),false);
sort(candidates.begin(),candidates.end());
backtrace(candidates,target,0,repeated);
return res;
}
};
131.分割回文串
整体逻辑是判断切割的字串是否为回文串,所以终止条件是遍历完整个字符串(if(s.size() == startID)。
class Solution {
public:
vector<string> path;
vector<vector<string>> ans;
bool isPalindrome(string s, int start, int end) {
for(int i = start, j = end; i < j; ++i, --j ) {
if(s[i]!=s[j]) return false;
}
return true;
}
void backtrace(string s, int startID) {
if(s.size() == startID) {
ans.push_back(path);
return;
}
for(int i = startID; i < s.size(); ++i) {
if(isPalindrome(s,startID,i)) {
auto str = s.substr(startID, i - startID + 1);
path.push_back(str);
}else{
continue;
}
backtrace(s,i+1);
path.pop_back();
}
}
vector<vector<string>> partition(string s) {
backtrace(s,0);
return ans;
}
};