40.组合总和Ⅱ
给定一个候选人编号的集合 candidates
和一个目标数 target
,找出 candidates
中所有可以使数字和为 target
的组合。
candidates
中的每个数字在每个组合中只能使用 一次 。
**注意:**解集不能包含重复的组合。
示例 1:
输入: candidates = [10,1,2,7,6,1,5], target = 8,
输出:
[
[1,1,6],
[1,2,5],
[1,7],
[2,6]
]
示例 2:
输入: candidates = [2,5,2,1,2], target = 5,
输出:
[
[1,2,2],
[5]
]
提示:
1 <= candidates.length <= 100
1 <= candidates[i] <= 50
1 <= target <= 30
代码:
开心的写完,发现172/176,最后测试:[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],target =30.内存超过限制
class Solution {
public:
vector<vector<int>> res;
vector<int> combine;
void backtracking(vector<int>& candidates, int &target,int index,int& sum){
if(sum==target){
res.push_back(combine);
return;
}
if(sum>target)
return;
for(int i=index;i<candidates.size();i++){
sum+=candidates[i];
combine.push_back(candidates[i]);
backtracking(candidates,target,i+1,sum);
sum-=candidates[i];
combine.pop_back();
}
}
void remove(vector<vector<int>> &res){//去重
set<vector<int>> a;
for(auto & v:res){
sort(v.begin(),v.end());
a.insert(v);
}
res.assign(a.begin(),a.end());
}
vector<vector<int>> combinationSum2(vector<int>& candidates, int target) {
int sum=0;
for(int i=0;i<candidates.size();i++){
sum+=candidates[i];
}
if(sum<target)
return res;
sum=0;
backtracking(candidates,target,0,sum);
remove(res);
return res;
}
};
发现是没剪枝优化
class Solution {
public:
vector<vector<int>> res;
vector<int> combine;
void backtracking(vector<int>& candidates, int &target,int index,int& sum){
if(sum==target){
res.push_back(combine);
return;
}
if(sum>target)
return;
for(int i=index;i<candidates.size();i++){
if(i>index&&candidates[i]==candidates[i-1])//剪枝,如果不写这个,会内存超限。原因是该搜索分枝重复,直接跳过
continue;
if(target<candidates[i])//剪枝,候选数字比目标更大,并且已经排好序了,后续只会越来越大。
break;
sum+=candidates[i];
combine.push_back(candidates[i]);
backtracking(candidates,target,i+1,sum);
sum-=candidates[i];
combine.pop_back();
}
}
void remove(vector<vector<int>> &res){//优化之后,不用再这样去重
set<vector<int>> a;
for(auto & v:res){
sort(v.begin(),v.end());
a.insert(v);
}
res.assign(a.begin(),a.end());
}
vector<vector<int>> combinationSum2(vector<int>& candidates, int target) {
int sum=0;
for(int i=0;i<candidates.size();i++){
sum+=candidates[i];
}
if(sum<target)
return res;
sum=0;
sort(candidates.begin(),candidates.end());
backtracking(candidates,target,0,sum);
// remove(res);
return res;
}
};
131.分割回文串
给你一个字符串 s
,请你将 s
分割成一些子串,使每个子串都是
回文串
。返回 s
所有可能的分割方案。
示例 1:
输入:s = "aab"
输出:[["a","a","b"],["aa","b"]]
示例 2:
输入:s = "a"
输出:[["a"]]
提示:
1 <= s.length <= 16
s
仅由小写英文字母组成
代码:
这道题,要解决两个问题?
- 怎么判断是不是回文串——双指针法即可
- 每一个答案都被穷举,说明要用回溯法,怎么用?
要清楚,正在处理pre=s.substr(0,i);
的和未处理的s.substr(i)
,看清楚,想清楚再用回溯法。
class Solution {
public:
vector<vector<string>> res;
vector<string> combine;
bool isHui(const string & pre) {//双指针法
int i=0;
int j=pre.length()-1;
while(i<=j) {
if(pre[i]!=pre[j]) {
return false;
}
i++;
j--;
}
return true;
}
void backtracking(string s) {
if(s.size() == 0) {
res.emplace_back(combine);
return;
}
for(int i = 1; i <= s.length(); i++) {
string pre=s.substr(0,i);//正要处理的
if(isHui(pre)) {
combine.push_back(pre);
backtracking(s.substr(i));//递归去看未处理的
combine.pop_back();
}
}
}
vector<vector<string>> partition(string s) {
if(s.length()==1) {//优化
combine.emplace_back(s);
res.emplace_back(combine);
return res;
}
backtracking(s);
return res;
}
};