代码随想录算法训练营day24 | 93.复原IP地址、78.子集、90.子集II
93.复原IP地址
点击查看代码
class Solution {
public:
vector<string> result;
//检查切割下来的区间[startIndex, endIndex]是否为合法IP字段
bool isValidIP(string &s, int startIndex, int endIndex) {
//注意勿漏条件:endIndex < startIndex 否则会将x.y.z.这样的IP加入结果集
if(endIndex < startIndex || endIndex - startIndex + 1 > 4) return false;
if(s[startIndex] == '0' && endIndex - startIndex + 1 > 1) return false;
int sum = 0;
for(int i = startIndex; i <= endIndex; ++i) {
sum *= 10;
sum += s[i] - '0';
if(sum > 255) return false;
}
return true;
}
void backtracking(string &s, int startIndex, int pointNum) {
//合法才会加pointNum并进入递归,当pointNum == 3时,说明前三段合法,需要再额外检查第四段是否合法
if(pointNum == 3) {
if(isValidIP(s, startIndex, s.size() - 1)) result.push_back(s);
return;
}
for(int i = startIndex; i < s.size(); ++i) {
if(isValidIP(s, startIndex, i)) {
s.insert(i + 1, "."); //注意:即使只插入一个字符,第二个参数也需要写成字符串形式
}
else break; //出现非法后,本层循环直接结束,因为再往后切也必然非法
backtracking(s, i + 2, pointNum + 1); //注意加了'.',故下一层循环从i + 2开始切割
s.erase(i + 1, 1);
}
}
vector<string> restoreIpAddresses(string s) {
backtracking(s, 0, 0);
return result;
}
};
78.子集
点击查看代码
class Solution {
public:
vector<vector<int>> result;
vector<int> path;
void backtracking(vector<int>& nums, int startIndex) {
//子集问题需要收集树中所有节点,即每选取一个元素
//收集必须在递归终止判断之前,否则当收集的是最后一个元素时,传进来的startIndex
//必然等于nums.size(),导致还没收集就return了
result.push_back(path);
if(startIndex == nums.size()) return;
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) {
backtracking(nums, 0);
return result;
}
};
组合和分割是收集叶子节点,而子集问题需要收集树上所有节点(即每选完一个数字就收集)
90.子集II
与上题相比增加了对原始nums数组进行排序和去重逻辑
点击查看代码
class Solution {
public:
vector<vector<int>> result;
vector<int> path;
void backtracking(vector<int>& nums, int startIndex) {
//子集问题需要收集树中所有节点,即每选取一个元素
//收集必须在递归终止判断之前,否则当收集的是最后一个元素时,传进来的startIndex
//必然等于nums.size(),导致还没收集就return了
result.push_back(path);
if(startIndex == nums.size()) return;
for(int i = startIndex; i < nums.size(); ++i) {
//去重逻辑:每层循环从第二个元素开始去重
//同一个层for循环进行去重即树层去重,树枝不去重
//对比78.子集只多了对原始nums进行排序和下面这句去重逻辑
if(i > startIndex && nums[i] == nums[i - 1]) continue;
path.push_back(nums[i]);
backtracking(nums, i + 1);
path.pop_back();
}
}
vector<vector<int>> subsetsWithDup(vector<int>& nums) {
//必须必须必须排序才能去重
sort(nums.begin(), nums.end());
backtracking(nums, 0);
return result;
}
};
2025/03/06

浙公网安备 33010602011771号