●93.复原IP地址
这道题跟回文子串切割差不多的结构,但是剪枝有好几个地方。
而且我这个用了path单独放子串,然后回溯用substr删除递归前面加上的子串,时间空间复杂度有点高。得再改进改进。
class Solution {
public:
string path;
vector<string> result;
int numPoint=0;//小数点的数量
void backtracking(const string &s,int startIndex){
if(startIndex==s.size() && numPoint==3){//numPoint>3的也被剪枝了
result.push_back(path);
return;
}
for(int i=startIndex;i<s.size();++i){
const string sub=s.substr(startIndex,i-startIndex+1);
if(sub.size()>3)continue;//剪枝1
long long num=stoi(sub);
if((sub[0]=='0'&&sub.size()>1)||num>255)continue;//剪枝2
path+=sub;
if(i<s.size()-1){
path+='.';
numPoint++;
}
backtracking(s,i+1);
int len=i-startIndex+1;
if(i<s.size()-1){
path=path.substr(0,path.size()-len-1);
numPoint--;
}
else path=path.substr(0,path.size()-len);
}
}
vector<string> restoreIpAddresses(string s) {
backtracking(s,0);
return result;
}
};
●78.子集
结构图如下,和之前的组合子串等的区别就是:组合问题和分割问题都是收集树的叶子节点,而子集问题是找树的所有节点!(代码随想录原话)。
所以在函数开头不能写递归出口return出去,而是无论什么节点,都要加入到result里面。所以任何节点都是完整执行函数的开头到结尾才会退出。
class Solution {
public:
vector<int> path;
vector<vector<int>> result;
void backtracking(vector<int>& nums,int startIndex){
// if(startIndex==index){
// return;
// }
result.push_back(path);
for(int i=startIndex;i<nums.size();++i){
path.push_back(nums[i]);
backtracking(nums,i+1);
path.pop_back();
}
}
vector<vector<int>> subsets(vector<int>& nums) {
//result.push_back(path);
backtracking(nums,0);
return result;
}
};
●90.子集II
就是●78.子集和● 40.组合总和II的结合,没有新的东西,必须秒了。
class Solution {
public:
vector<int> path;
vector<vector<int>> result;
void backtracking(vector<int>& nums,int startIndex,vector<bool> &used){
result.push_back(path);
for(int i=startIndex;i<nums.size();++i){
if(i>0 && nums[i]==nums[i-1] && used[i-1]==false)//剪枝
{
continue;
}
path.push_back(nums[i]);
used[i]=true;
backtracking(nums,i+1,used);
used[i]=false;
path.pop_back();
}
}
vector<vector<int>> subsetsWithDup(vector<int>& nums) {
vector<bool> used(nums.size());
sort(nums.begin(),nums.end());
fill(used.begin(),used.end(),false);
backtracking(nums,0,used);
return result;
}
};