93.复原IP地址、78.子集、90.子集Ⅱ
93.复原IP 地址
这道题与昨天的回文子串很像,
我们可以创建一个函数bool isip(string& ss,int start,int end)
,
来判断此次分割的字符串是否是介于【0,255】。输入的参数包括
string ss, 题目所给的字符串ss,
int start,需要判断的字符串的起始位置,
int end,需要判断的字符串的末尾位置。
对于该函数,如果起始位置是零,并且end!=start,表示需要判断的字符串不只一位,且首位是零。因此我们直接返回false就行。不然,我们就将这个字符串转化为int类型,再判断。定义一个int类型num=0;对于字符串的每一位,我们都先让num*10,再加上这个字符代表的数字。
bool isip(string& ss,int start,int end)
{
if(ss[start]=='0'&&start!=end||start>end) return false;
int num=0;
for(int ii = start;ii<=end;ii++)
{
num*=10;
num+=(ss[ii]-'0');
}
if(num>255) return false;
return true;
}
对于给定的字符串ss,如果它的大小小于4,或者大于12,我们直接返回空字符串数组(分成四份的话,至少保证每份至少有一位数至多三位数)。
最重要的是回溯递归。
我们需要提前确定参数,首先是字符串本身,然后是每次循环的起始位置,最后是插入的点的个数。
所以回溯函数定为void backtracking(string& ss,int start,int point)
如果point==3,我们先判断最后的字符串是不是合法的,如果合法,我们直接将结果加入到result;
不然,我们从起始位置进行循环,最多循环三位数(保证循环的ii不超过字符串大小),让子符串在ii+1的位置插入一个‘.’,并且让point++;然后进行回溯,回溯结束后,把这个‘.’删除,point–即可。
代码
class Solution {
public:
vector<string> result;
bool isip(string& ss,int start,int end)
{
if(ss[start]=='0'&&start!=end||start>end) return false;
int num=0;
for(int ii = start;ii<=end;ii++)
{
num*=10;
num+=(ss[ii]-'0');
}
if(num>255) return false;
return true;
}
void backtracking(string& ss,int start,int point)
{
if(point ==3)
{
if(isip(ss,start,ss.size()-1))
result.push_back(ss);
}
else{
for(int ii = start;ii<start+3&&ii<ss.size();ii++)
{
if(!isip(ss,start,ii))
break;
else
{
ss.insert(ss.begin()+ii+1,'.');
point++;
backtracking(ss,ii+2,point);
point--;
ss.erase(ss.begin()+ii+1);
}
}
}
}
vector<string> restoreIpAddresses(string s) {
if(s.size()<4||s.size()>12)
return result;
backtracking(s,0,0);
return result;
}
};
78.子集
对于子集,我们定义全局变量
二维变量vector<vector<int>> result;
用于存储结果。
一维变量vector<int> temp;
用于存储当前的数组元素。
如果给定的数组为空,我们就给result加入一个空数组,当作子集,直接输出。
如果不为空,就进行递归回溯。
我们递归回溯过程,我们直接将temp加入到result中(空集,全集也是子集),并从起始位置进行循环,将result【ii】加入到temp,并从下一位置进行递归,递归结束就把加入的元素弹出来。
代码
class Solution {
public:
vector<vector<int>> result;
vector<int> temp;
void backtracking(vector<int>&nums,int start)
{
result.push_back(temp);
for(int ii = start;ii<nums.size();ii++)
{
temp.push_back(nums[ii]);
backtracking(nums,ii+1);
temp.pop_back();
}
}
vector<vector<int>> subsets(vector<int>& nums) {
if(nums.empty())
{
result.push_back(temp);
return result;
}
backtracking(nums,0);
return result;
}
};
90.子集Ⅱ
该问题是子集问题和组合总和问题的组合形式,既要求子集,所给数组还有重复元素,还要避免答案中组合重复。
因此,我们先判断该数组,如果为空,返回一个含空集的数组。
如果不为空,就进行递归回溯,
递归回溯中,我们先将temp放入到result之中,进行for循环递归,同组合问题一样,为了避免重复访问相同数字,如果不是start,我们就避免其与前一个元素相同,用while循环对循环下标进行++。
class Solution {
public:
vector<vector<int>>result;
vector<int>temp;
void backtracking(vector<int>nums,int start)
{
result.push_back(temp);
for(int ii =start;ii<nums.size();ii++)
{
if(ii>start)
{
while(ii<nums.size()&&nums[ii]==nums[ii-1])
ii++;
}
if(ii<nums.size())
{
temp.push_back(nums[ii]);
backtracking(nums,ii+1);
temp.pop_back();
}
}
}
vector<vector<int>> subsetsWithDup(vector<int>& nums) {
if(nums.size()==0)
{
result.push_back(temp);
return result;
}
sort(nums.begin(),nums.end());
backtracking(nums,0);
return result;
}
};