题目出处:https://leetcode-cn.com/problems/restore-ip-addresses/
思路:回溯+减枝解决。题目中的字符串全为数字构成,需要处理字符串为0开头的情况。
- 递归函数dfs(duan, startpos, oneAns):代表IP地址的第duan个字符串,duan属于{0,1,2,3};startpos代表第duan+1个字符串的首地址,oneAns代表满足题目条件的一个IP地址划分。
- 递归终止条件:如果duan==4&&startPos = n说明字符串中的所有字符都参与了划分,且被划分成四段,即此时找到一个满足条件的IP地址。
- 剪枝条件:若没遍历完字符串中的全部字符就已经找出一个IP,就提前结束搜索。
- 递归函数体:从字符串的首字符开始遍历,IP地址的每一段都不能超过三个字符,因此枚举以s[startpos]为首字符,长度为1,2,3的字符串,并判断字符串代表的数值是否在[0,255]中;由于IP地址的每一段都不能含有前导0,所以若s[startpos]为0,则单独为一个IP段。因此,实现过程中以s[startpos]是否为0进行两种情况的划分。
class Solution {
private:
vector<string> ans;
public:
bool check(string& s){
int s_num = atoi(s.c_str());
if(s_num >= 0 && s_num <= 255){
return true;
}
return false;
}
void dfs(int duan, int startPos, string &s, vector<string> &oneAns, int & n){
if(duan == 4 && startPos == n){
string res = "";
for(int i = 0; i < 3; ++i){
res += oneAns[i]+'.';
}
res += oneAns[3];
ans.push_back(res);
return;
}
if(duan == 4){ //减枝,没遍历完字符串就找到了IP的四段,就提前结束搜索
return;
}
if(s[startPos] != '0'){ //不含有前导0
for(int len = 1; len <= 3 && startPos+len <= n; ++len){ //注意startPos+len <= n有等号
string now_seg = s.substr(startPos, len);
if(check(now_seg)){
oneAns.push_back(now_seg);
dfs(duan+1, startPos+len, s, oneAns, n);
oneAns.pop_back();
}
}
}
else{ //含有前导0
string now_seg = "";
now_seg.push_back(s[startPos]); //char转换成string的方式,用push_back()
oneAns.push_back(now_seg);
dfs(duan+1, startPos+1, s, oneAns, n);
oneAns.pop_back();
now_seg.pop_back();
}
}
vector<string> restoreIpAddresses(string s) {
int n = s.length();
if(n <= 3){
return ans;
}
int duan = 0, startPos = 0;
vector<string> oneAns;
dfs(duan, startPos, s, oneAns, n);
return ans;
}
};
//注意startPos+len <= n有等号的原因
如 s = “1111”,startpos = 1, len = 3, s.substr(startpos, len) = “111”,此时startpos+len == 4 == s.length() = 4;