93.复原IP地址
思路
子串分割问题:
第一反应是用组合思路分割字符串再放入path路径最后放入result结果集,但是操作有点繁琐,只需插入分割点‘.’即可解决。
- 分割子串
startIndex记录子串起始位置,for循环向后遍历,取不同长度子串。
for (int i = startIndex; i < s.size(); i++) {}
- 循环终止条件
当已经插入三个‘.’,此时只需要判断留下的最后一个子串是否符合条件。
if (pointNum == 3) {
if (isValid(s, startIndex, s.size() - 1)) {
result.push_back(s);
}
return;
}
- 递归回溯操作
先判断当前分割出的子串是否符合条件
符合条件则可以在分割的子串后插入分割点,然后继续向后递归。回溯操作即为撤销插入的分割点
不符合条件则终止当前循环,继续分割新的子串
if (isValid(s, startIndex, i)) {
s.insert(s.begin() + i + 1 , '.');
pointNum++;
backtracking(s, i + 2);
pointNum--;
s.erase(s.begin() + i + 1);
} else break;
}
- 判断子串是否符合条件
传入的参数为字符串s,起始位置start,终止位置end- 当start>end,不符合条件
- 当字符串以0为起始,即s[start]=‘0’&&start!=end,不符合条件
- 当字符串内有不合法字符,不符合条件
- 当字符串表示数值大于255,不符合条件
bool isValid(const string& s, int start, int end) {
int num=0;
if(start>end)return false;
if(s[start]=='0'&&start!=end)return false;
for(int i=start;i<=end;i++){
if(s[i]<'0'||s[i]>'9')return false;
num*=10;
num+=s[i]-'0';
if(num>255)return false;
}
return true;
}
- 剪枝
当字符串长度大于12或者小于4时,肯定是不合法的IP地址
if (s.size() < 4 || s.size() > 12) return result;
代码实现
class Solution {
private:
vector<string> result;
int pointNum=0;
void backtracking(string& s, int startIndex ) {
if (pointNum == 3) {
if (isValid(s, startIndex, s.size() - 1)) {
result.push_back(s);
}
return;
}
for (int i = startIndex; i < s.size(); i++) {
if (isValid(s, startIndex, i)) {
s.insert(s.begin() + i + 1 , '.');
pointNum++;
backtracking(s, i + 2);
pointNum--;
s.erase(s.begin() + i + 1);
} else break;
}
}
bool isValid(const string& s, int start, int end) {
int num=0;
if(start>end)return false;
if(s[start]=='0'&&start!=end)return false;
for(int i=start;i<=end;i++){
if(s[i]<'0'||s[i]>'9')return false;
num*=10;
num+=s[i]-'0';
if(num>255)return false;
}
return true;
}
public:
vector<string> restoreIpAddresses(string s) {
result.clear();
if (s.size() < 4 || s.size() > 12) return result;
backtracking(s,0);
return result;
}
};
78.子集
思路
集合问题:操作和组合问题差不多,组合问题中path路径存入的每一步都是一个子集,所以用result保存path的每一步操作即可,该题目没有重复元素,所以不需要去重操作。
代码实现
vector<vector<int>> result;
vector<int> path;
void backtracking(vector<int> &nums,int startIndex){
if(startIndex==nums.size())return ;
for(int i=startIndex;i<nums.size();i++){
path.push_back(nums[i]);
result.push_back(path);
backtracking(nums,i+1);
path.pop_back();
}
return;
}
vector<vector<int>> subsets(vector<int>& nums) {
backtracking(nums,0);
result.push_back(path);
return result;
}
90.子集II
思路
集合问题:和组合问题的去重操作一样,但要记得先把集合内元素排序
代码实现
class Solution {
public:
vector<vector<int>> result;
vector<int> path;
void backtracking(vector<int> &nums,int startIndex,vector<int> &used){
if(startIndex==nums.size())return ;
for(int i=startIndex;i<nums.size();i++){
if(i>0&&nums[i]==nums[i-1]&&used[i-1]==0)continue;
path.push_back(nums[i]);
used[i]=1;
result.push_back(path);
backtracking(nums,i+1,used);
used[i]=0;
path.pop_back();
}
return;
}
vector<vector<int>> subsetsWithDup(vector<int>& nums) {
vector<int> used(nums.size(),0);
sort(nums.begin(),nums.end());
backtracking(nums,0,used);
result.push_back(path);
return result;
}
};
总结
分割问题