93. 复原 IP 地址
递归参数:index一定是需要的,记录下一层递归分割的起始位置。还需要一个变量pointNum,记录添加逗点的数量。
递归终止条件:明确要求只会分成4段,所以不能用切割线切到最后作为终止条件,而是分割的段数作为终止条件。pointNum表示逗点数量,pointNum为3说明字符串分成了4段了。然后验证一下第四段是否合法,如果合法就加入到结果集里
单层搜索的逻辑:在for (int i = startIndex; i < s.size(); i++)
循环中 [startIndex, i] 这个区间就是截取的子串,需要判断这个子串是否合法。如果合法就在字符串后面加上符号.
表示已经分割。如果不合法就结束本层循环,剪掉的分支。递归调用时,下一层递归的startIndex要从i+2开始(因为需要在字符串中加入了分隔符.
),同时记录分割符的数量pointNum 要 +1。回溯的时候,就将刚刚加入的分隔符.
删掉就可以了,pointNum也要-1。
出现问题
1.直接进行简单的判断s[start]==0,并没有判断出现0时候的位置
2.区间定义出现问题,isBaild里面函数是左闭右闭区间,然而在调用函数时进去的是左闭右开区间
class Solution {
public:vector<string> res;bool isValid(string &s,int start,int end){if(start>end)return false;if(s[start]=='0' && start != end)return false;int num=0;while(start<=end){if(s[start]<'0'||s[start]>'9')return false;num = num * 10 + (s[start] - '0');if(num>255)return false;start++;}return true;}void backtracing(string &s,int index,int pointnum){if(pointnum==3){if(isValid(s,index,s.size()-1)){res.push_back(s);return; } }for(int i=index;i<s.size();i++){if(isValid(s,index,i)){s.insert(s.begin() + i + 1 , '.'); // 在i的后面插入一个逗点pointnum++;backtracing(s, i + 2, pointnum); // 插入逗点之后下一个子串的起始位置为i+2pointnum--; s.erase(s.begin() + i + 1); }}}vector<string> restoreIpAddresses(string s) {res.clear();backtracing(s,0,0);return res;}
};
78. 子集
如果把 子集问题、组合问题、分割问题都抽象为一棵树的话,那么组合问题和分割问题都是收集树的叶子节点,而子集问题是找树的所有节点!
那么既然是无序,取过的元素不会重复取,写回溯算法的时候,for就要从index开始,而不是从0开始!
递归函数参数:全局变量数组path为子集收集元素,二维数组res存放子集组合。
递归终止条件:前面直接if(index<nums.size()),出现结果空集的情况,后面仔细一想,不用终止条件是不是也行
单层搜索逻辑:求取子集问题,不需要任何剪枝!因为子集就是要遍历整棵树。
class Solution {
public:vector<vector<int>> res;vector<int> path;void backtracking(vector<int> &nums, int index){res.push_back(path);for(int i=index;i<nums.size();i++){path.push_back(nums[i]);backtracking(nums,i+1);path.pop_back();}}vector<vector<int>> subsets(vector<int>& nums) {res.clear();path.clear();backtracking(nums,0);return res;}
};
90. 子集 II
从图中可以看出,同一树层上重复取2 就要过滤掉,同一树枝上就可以重复取2,因为同一树枝上元素的集合才是唯一子集!
递归函数参数:全局变量数组path为子集收集元素,二维数组res存放子集组合。需要一个used数组用于去重。
递归终止条件:子集问题可以不用写
单层搜索逻辑:求取子集问题,不需要任何剪枝!因为子集就是要遍历整棵树
class Solution {
public:vector<int> path;vector<vector<int>> res;void backtracking(vector<int>& nums, int index,vector<bool> used){res.push_back(path);for(int i=index;i<nums.size();i++){if(i>0&&nums[i]==nums[i-1]&&used[i-1]==false) continue;used[i]=true;path.push_back(nums[i]);backtracking(nums,i+1,used);used[i]=false;path.pop_back();}}vector<vector<int>> subsetsWithDup(vector<int>& nums) {vector<bool> used(nums.size(),false);path.clear();res.clear();sort(nums.begin(),nums.end());backtracking(nums,0,used);return res;}
};