十道回溯剪枝就这一道难的,感觉重回pat那时候的字符串大模拟,不过确实是好题。
用一个vector来存每个字段的数字即可,这样可以在最后在进行IP地质的拼接。
这道题最重要的就是剪枝。递归边界就是tmp.size()==4了,如果s用完了,就将tmp数组里的字符串拼接成IP地址即可。然后不管是否用完s,都要return了。
从当前位开始最多往后取3位,从1遍历到3。此时第一个剪枝操作:如果当前起始字符+要截取的字符长度越界了,直接return。第二个剪枝操作:截取的这一字段的字符串对应的数字大于255也return。第三个剪枝操作:最重要的前导0,如果当前不是截取当前位的第一个数字,也就是i>1而且当前字段的第一位为0,直接return。
将截取的字段加入tmp然后进行dfs,记得手动弹出
class Solution {
public:
void dfs(string s, int start){
if(tmp.size() == 4){
if(start == s.length()){
string str = tmp[0];
for(int i = 1; i < tmp.size(); ++i){
str += "."+tmp[i];
}
res.push_back(str);
}
//如果没有用完s,直接return,如果用完s在进行完操作后也要return
return;
}
//从当前位往后最多再取三位,i=1包括取的是当前的所以判断越界要注意
for(int i = 1; i <= 3; ++i){
//start+i==length是被允许的
if(start + i - 1 >= s.length()) return;
//如果当前截取的字符串大小大于255也return
if(stoi(s.substr(start,i)) > 255) return;
//如果当前有前导0的也直接return
//也就是第一位是0,而且现在进行到第一位之后了,证明你企图截取01,012这种
if(s[start] == '0' && i != 1) return;
//如果上面的都不满足,就证明是一个合格的字节
tmp.push_back(s.substr(start,i));
dfs(s,start+i);
tmp.pop_back();//这一步回溯很重要,你想要没有这一步,就把tmp作为变量来传递,会自动pop_back
}
}
vector<string> restoreIpAddresses(string s) {
//dfs+回溯,用一个vector来存当前组成IP地址的字段,当等于4且s用完了,就补上中间的.号然后加入res中
if(s.length() < 4 || s.length() > 12) return res;
dfs(s,0);
return res;
}
private:
vector<string> res;
vector<string> tmp;
};