LeetCode 93. 复原 IP 地址
思路:
这道题目和131.分割回文串十分相似,都是分割子字符串,基本做法也是一致的,只不过在判断和结束递归的条件有不同。因为ip地址由四个数构成,所以可以用一个string的数组记录,当数组达到长度4的时候,并且左指针走到了字符串的尾部,则说明这是一个合法的ip地址,记录在最终结果里并返回,反之如果长度为4并且左指针没有走到末尾,则直接返回,因为无论剩下的字符串内容是什么,记录ip地址的数组长度都会超过4,所以不合法。
另外判断单个组成ip地址的数是否合法的条件有两个,一个是stoi(num) <=255,因为不会出现负数所以不需要做>=0的判断。其次是数字首位不能为0,所以当数字首位为0并且数字的位数不为1时直接跳过,当且仅当数字只有一位的时候,数字首位才能为0。最后需要做一个剪枝,因为数字的位数不会超过255,所以数字位数最多只有3位。当子字符串长度超过3时,转换成的数字一定超过255,可以直接break跳过整个数层。
代码:
class Solution {
public:
vector<string> path;
vector<string> ans;
vector<string> restoreIpAddresses(string s) {
backtracking(s, 0);
return ans;
}
void backtracking(string s, int left)
{
if (path.size() == 4 && left == s.size())
{
string temp;
for (int i = 0; i < 3; i++)
{
temp.append(path[i]);
temp.push_back('.');
}
temp.append(path[3]);
ans.push_back(temp);
return;
}
else if (path.size() == 4 || left == s.size())
return;
for (int i = left; i < s.size(); i++)
{
// 当子字符串长度大于3时剪枝
if (i - left >= 3)
break;
string temp;
for (int j = left; j <= i; j++)
temp.push_back(s[j]);
// 当子字符串长度大于1并且首位为0时剪枝
if (temp[0] == '0' && temp.size() > 1)
continue;
if (stoi(temp) <= 255)
{
path.push_back(temp);
backtracking(s, i + 1);
path.pop_back();
}
}
}
};
LeetCode 78. 子集
思路:
像这种寻找数组幂集的题目,相当于把树的每个节点的答案都算进去了,所以在每个节点都把答案push进最终结果即可,除此之外,这道题目就是一道标准的找组合的模板题。用一张图可以更清晰的表示子集是如何取每个节点的值的:
借用代码随想录的一句话:子集是收集树形结构中树的所有节点的结果。而组合问题、分割问题是收集树形结构中叶子节点的结果。
代码:
class Solution {
public:
vector<int> path;
vector<vector<int>> ans;
vector<vector<int>> subsets(vector<int>& nums) {
// 先把空集push进去
ans.push_back(path);
backtracking(nums, 0);
return ans;
}
void backtracking(vector<int>& nums, int idx)
{
if (idx == nums.size())
return;
for (int i = idx; i < nums.size(); i++)
{
path.push_back(nums[i]);
// 每个节点都要push
ans.push_back(path);
backtracking(nums, i + 1);
path.pop_back();
}
}
};
LeetCode 90. 子集 II
思路:
和上一题一模一样的套路,唯一的区别是nums数组里的值可能会有重复,这道题中去重的步骤其实和40.组合总和II的逻辑是一样的,都是检查nums[i]是否等于nums[i-1]然后再判断是否可以在树层剪枝,当i>idx则说明是树层。
代码:
class Solution {
public:
vector<int> path;
vector<vector<int>> ans;
vector<vector<int>> subsetsWithDup(vector<int>& nums) {
ans.push_back(path);
// 需要排序
sort(nums.begin(), nums.end());
backtracking(nums, 0);
return ans;
}
void backtracking(vector<int>& nums, int idx)
{
if (idx == nums.size())
return;
for (int i = idx; i < nums.size(); i++)
{
if (i > idx && nums[i] == nums[i-1])
continue;
path.push_back(nums[i]);
ans.push_back(path);
backtracking(nums, i + 1);
path.pop_back();
}
}
};