93.复原IP地址
思路
是一个细节比较多的题目,第一遍做起来比较吃力,主要需要注意以下几个点:
- 二叉树深度的确定其实是靠加的分隔符
.
的数目确定的,因此传参时需要传递pointNum
。 - 在达成终止条件后,还要判断分割后的第四段字符串是否合法,需设计
isValid
函数。 isValid
函数主要包括这几个功能:是否在0~255
的区间内,是否不是0
开头的多位数,每一位数字是否在(0~9)的范围内。在求num
的过程中运用到了类似移位的思想:num = num * 10 + (s[i] - '0')
。- 并没有创造额外空间,而是在字符串
s
的基础上进行insert
操作,c++中的insert
参数需要是s.begin() + i + 1
。 - 在回溯设计时,回溯函数不在是
i + 1
,因为插入了逗点,所以应该是backtracking(s, i + 2, pointSum)
。
代码随想录
class Solution {
private:
string path;
vector<string> result;
bool isValid(string& s, int start, int end) {
if (start > end) return false;
// 当 0 开头且不是 0 单独出现时,例如 012 为非法
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;
}
void backtracking(string& s, int startIndex, int pointSum) {
// 逗点控制树的深度
if (pointSum == 3) {
// 对最后一段进行合法性判断
if (isValid(s, startIndex, s.size() - 1)) {
// 直接在 s 的基础上加逗点进行切割
result.push_back(s);
return;
}
}
// 每一层中 startIndex 是固定的,随着 i 向后移动切割区间开始发生变化
for (int i = startIndex; i < s.size(); i ++) {
if (isValid(s, startIndex, i)) {
s.insert(s.begin() + i + 1, '.');
pointSum ++;
backtracking(s, i + 2, pointSum); // 加了个逗点,所以这里要加2
s.erase(s.begin() + i + 1);
pointSum --;
}else break;
}
}
public:
vector<string> restoreIpAddresses(string s) {
result.clear();
backtracking(s, 0, 0);
return result;
}
};
78.子集
思路
- 想明白本题是要收集所有节点的值就简单了
代码随想录
class Solution {
private:
vector<int> path;
vector<vector<int>> result;
void backtracking(vector<int>& nums, int startIndex) {
result.push_back(path);
// 如何记录每一个节点: 即在回溯函数的开始即收集 path,不再设计终止条件
for (int i = startIndex; i < nums.size(); i ++) {
path.push_back(nums[i]);
backtracking(nums, i + 1);
path.pop_back();
}
}
public:
vector<vector<int>> subsets(vector<int>& nums) {
path.clear();
result.clear();
backtracking(nums, 0);
return result;
}
};
90.子集II
思路
- 在上一道题的基础上增加了层内去重操作,运用
used
数组或i > startIndex
进行判断均可
代码随想录
class Solution {
private:
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 && used[i - 1] == false && nums[i] == nums[i-1]) {
continue;
}
path.push_back(nums[i]);
used[i] = true;
backtracking(nums, i + 1, used);
path.pop_back();
used[i] = false;
}
}
public:
vector<vector<int>> subsetsWithDup(vector<int>& nums) {
path.clear();
result.clear();
vector<bool> used(nums.size(), false);
sort(nums.begin(), nums.end());
backtracking(nums, 0, used);
return result;
}
};