有效 IP 地址 正好由四个整数(每个整数位于 0
到 255
之间组成,且不能含有前导 0
),整数之间用 '.'
分隔。
- 例如:
"0.1.2.201"
和"192.168.1.1"
是 有效 IP 地址,但是"0.011.255.245"
、"192.168.1.312"
和"192.168@1.1"
是 无效 IP 地址。
给定一个只包含数字的字符串 s
,用以表示一个 IP 地址,返回所有可能的有效 IP 地址,这些地址可以通过在 s
中插入 '.'
来形成。你 不能 重新排序或删除 s
中的任何数字。你可以按 任何 顺序返回答案。
class Solution {
public:
vector<string> result;
bool isValid(string& s, int left, int right){
if (left > right)
return false;
if (s[left] == '0' && left != right)
return false;
int num = 0;
for (int i = left; i <= right; i++){
if (s[i] <'0' || s[i] > '9')
return false;
num = num * 10 + (s[i] - '0');
if (num > 255)
return false;
}
return true;
}
void backtracking(string& s, int startIndex, int pointNum){
if (pointNum == 3){
if (isValid(s, startIndex, s.length() - 1))
result.push_back(s);
return;
}
for (int i = startIndex; i < s.length(); i++){
if (isValid(s, startIndex, i)){
s.insert(s.begin() + i + 1, '.');
pointNum++;
backtracking(s, i + 2, pointNum);
pointNum--;
s.erase(s.begin() + i + 1);
}
else
break;
}
}
vector<string> restoreIpAddresses(string s) {
if (s.size() < 4 || s.size() > 12) return result; // 算是剪枝了
backtracking(s, 0, 0);
return result;
}
};
其实只要意识到这是切割问题,切割问题就可以使用回溯搜索法把所有可能性搜出来.
回溯三部曲:
递归参数:
startIndex一定是需要的,因为不能重复分割,记录下一层递归分割的起始位置。
本题我们还需要一个变量pointNum,记录添加逗点的数量。
递归函数的终止条件:
pointNum表示逗点数量,pointNum为3说明字符串分成了4段了。
然后验证一下第四段是否合法,如果合法就加入到结果集里
单层搜索逻辑:
在for (int i = startIndex; i < s.length(); i++)
循环中 [startIndex, i] 这个区间就是截取的子串,需要判断这个子串是否合法。
如果合法就在字符串后面加上符号.
表示已经分割。
如果不合法就结束本层循环。
递归调用时,下一层递归的startIndex要从i+2开始(因为需要在字符串中加入了分隔符.
),同时记录分割符的数量pointNum 要 +1。
回溯的时候,就将刚刚加入的分隔符.
删掉就可以了,pointNum也要-1。
判断子串是否合法:
最后就是在写一个判断段位是否是有效段位了。
主要考虑到如下三点:
- 段位以0为开头的数字不合法
- 段位里有非正整数字符不合法
- 段位如果大于255了不合法
- 参考:代码随想录 (programmercarl.com)