Leetcode - 93:复原IP地址:
这道题经历了无数bug,但主要bug还是出在了判断子串是否合法上:
(一)、循环条件:
这里我们传入的参数是题目给定字符串s以及子串的开始点和结束点:start、end。所以首先我们在判断子串开头为0的非法情况时我们要判断的是s[start]而不是s[0],不能混淆了传入的s是原字符串!!
(二)、特殊情况判定:
我一开始觉得end<start没有必要加进去,因为i是从start开始遍历直到s.size(),但这里由于插入了'.'的缘故导致我们下一次递归是从i+2开始的所以可能会越过end边界,导致第四个子串为空但依然通过了合法判定。也就是下面这种情况:
["1.0.10.23","1.0.102.3","10.1.0.23","10.10.2.3","10.10.23.","10.102.3.","101.0.2.3","101.0.23."]
["1.0.10.23","1.0.102.3","10.1.0.23","10.10.2.3","101.0.2.3"]
完整代码如下:
class Solution {
public:
vector<string> res;
// 直接对s进行处理不在使用path
void solve(string& s, int start, int count){
if(count == 3){
if(isvalid(s, start, s.size() - 1)){
res.push_back(s);
}
return;
}
for(int i = start; i < s.size(); i++){
if(isvalid(s, start, i)){
s.insert(s.begin() + i + 1, '.');
solve(s, i + 2, count + 1);
s.erase(s.begin() + i + 1);
}else break;
}
}
bool isvalid(string& s, int start, int end){
if(end < start) return false;
if(s[start] == '0' && start != end) return false;
int num = 0;
for(int i = start; i <= end; i++){
if(s[i] > '9' || s[i] < '0') return false;
num = num * 10 + (s[i] - '0');
if(num > 255) return false;
}
return true;
}
vector<string> restoreIpAddresses(string s) {
solve(s, 0, 0);
return res;
}
};
Leetcode - 78:子集
排列问题for循环就要从0开始遍历,而组合问题需要从标记点start开始遍历即可。
由于回溯的特性所以让我们可以选择到1、2和1、3这样的组合,因为遍历完1、2组合后会自动回溯到上一状态1,然后i++遍历后面的元素3。
记住这一点:横向选择为for循环控制,纵向遍历是有递归控制。
这道题就是普通的组合题加上一个条件:在每一次递归的时候直接加入到res数组中,不在等他遍历到叶子的事后再加入了。
class Solution {
public:
vector<int> path;
vector<vector<int>> res;
void solve(const vector<int>& s, int start){
res.push_back(path);
if(start > s.size() - 1){
return;
}
for(int i = start; i < s.size(); i++){
path.push_back(s[i]);
solve(s, i + 1);
path.pop_back();
}
}
vector<vector<int>> subsets(vector<int>& nums) {
solve(nums, 0);
return res;
}
};
Leetcode - 90 子集II:
这道题就是之前的组合II与子集的结合版,就是需要进行树层去重。这里我们有一点需要注意一下就是在solve函数内,我们的终止条件是start > size,但是我们可以考虑当start>size时下面的单层循环就不执行了,所以可以去点这一判定语句,减少了大量的实行时间。
class Solution {
public:
vector<int> path;
vector<vector<int>> res;
vector<bool> used;
void solve(const vector<int>& s, int start){
res.push_back(path);
for(int i = start; i < s.size(); i++){
// 此时used的第一层已经回溯到了false状态
if(i > 0 && s[i] == s[i - 1] && used[i - 1] == false){
continue;
}
path.push_back(s[i]);
used[i] = true;
solve(s, i + 1);
used[i] = false;
path.pop_back();
}
}
vector<vector<int>> subsetsWithDup(vector<int>& nums) {
res.clear();
path.clear();
sort(nums.begin(), nums.end());
used.assign(nums.size(), false);
solve(nums, 0);
return res;
}
};