day28
93.复原IP地址
题目链接:93. 复原 IP 地址
回溯抽象为树结构,for横向遍历,递归纵向遍历,本题直接在字符串s
中进行修改,传入三个参数,一个字符串s一个开始索引,一个点计数,当点计数到达三个还需要判断是否最后一段合法,然后进行递归,注意递归时候i+2
,还有c++中的插入和删除的命令insert(s.begin()+i+1,’.’); erase(s.begin()+i+1)
-
如何判断字符串是否合法?
1.字符串中存在非法字符
2.字符串中有前导0
3.字符串中的数大于255了
nums = nums*10 + (s[i]-'0')
4.开头索引大于结尾索引
class Solution {
public:
//递归函数
// 定义结果数组
vector<string> result;
void backtracking(string& s,int startIndex,int pointsum){ //还加const呢,被修改了 隔着卡半天
// 确定终止条件
if ( pointsum == 3){
if(isVaild(s,startIndex,s.size()-1)){
// 这里是判断最后一个分割点之后的元素,如255.255.255.368 判断369
result.push_back(s);
return;
}
}
// 单层遍历逻辑
for( int i = startIndex; i < s.size(); i++){
if(isVaild(s,startIndex,i)){
// cout<<s[i]<<endl;
// s.insert(s.begin()+i+1,'.');
s.insert(s.begin() + i + 1 , '.');
pointsum +=1;
// 递归
backtracking( s, i+2,pointsum); //这里应该用i+2因为已经插入了一个.
// 回溯
s.erase(s.begin()+i+1);
pointsum -= 1;
}
else{break;}
}
}
// 判断字符串是否合法
bool isVaild(const string& s,int start,int end){
if( start > end){
return false; //如果左区间大于右区间,不合法
}
if( s[start] == '0' && start != end){
//第一个数字为0不合法
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 ){ //大于255不合法
return false;
}
}
return true;
}
vector<string> restoreIpAddresses(string s) {
backtracking( s, 0,0);
return result;
}
};
78.子集
题目链接:78. 子集
和组合问题差不错,只是收获结果的方式不一样,需要在树的每一层都收获结果,因此注意收获结果的位置。
class Solution {
public:
// 定义结果数组
vector<vector<int>> result;
vector<int> path;
void backtracking( vector<int>& nums, int startIndex ){
// 开始收获结果
result.push_back(path); //可以理解为开始就把空集加进去
// 终止条件
if( startIndex >= nums.size()) return;
// 单层逻辑
for( int i = startIndex; i < nums.size(); i++){
path.push_back(nums[i]);
backtracking( nums, i+1);
path.pop_back();
}
}
vector<vector<int>> subsets(vector<int>& nums) {
backtracking( nums,0);
return result;
}
};
90.子集II
题目链接:90. 子集 II
解题思路:
子集的思路加上去重的逻辑,组合II那块去重的逻辑
class Solution {
public:
// 定义存放结果的全局变量
vector<int> path;
vector<vector<int>> result;
void backtracking( vector<int>& nums,int startIndex,vector<bool>used){
// 先收获结果
result.push_back(path);
if( startIndex >= nums.size()) return;
// 单层逻辑
for( int i = startIndex; i < nums.size(); i++){
if( i > 0 && nums[i] == nums[i-1] && !used[i-1]) continue; //确定前一个元素是否被使用过
path.push_back(nums[i]); //加入元素
used[i] = true;
backtracking(nums,i+1,used);
// 回溯
path.pop_back();
used[i] = false;
}
}
vector<vector<int>> subsetsWithDup(vector<int>& nums) {
// 对数组进行排序
sort( nums.begin(), nums.end()); //排序
vector<bool> used(nums.size(),false); //定义使用数组
backtracking( nums,0,used);
return result;
}
};