问题描述:
有效 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
中的任何数字。你可以按 任何 顺序返回答案。
思路:
-
定义函数和数据结构:定义一个名为
restoreIpAddresses
的函数,它接受一个字符串s
作为输入,并返回一个字符串向量,表示所有可能的有效 IP 地址。再定义一个辅助函数restoreIpAddressesDFS
,它用于执行深度优先搜索(DFS)。 -
初始化和终止条件:在
restoreIpAddresses
函数中,首先创建一个空的结果向量result
和一个空字符串ip
。然后调用restoreIpAddressesDFS
函数开始搜索有效的 IP 地址。DFS 函数中,需要考虑以下终止条件:-
如果已经遍历完整个字符串,并且已经找到了 4 个整数,则将结果加入到结果集中。
-
如果剩余字符数太多或太少,无法凑成一个 IP 地址,则不再继续搜索。
-
-
深度优先搜索:在
restoreIpAddressesDFS
函数中,从start
索引开始,尝试将连续的 1 到 3 个字符解释为一个整数。使用一个循环来尝试不同长度的整数,同时确保整数的值在 0 到 255 之间。在每次尝试后,我们将得到的整数加入到ip
字符串中,并递归地调用restoreIpAddressesDFS
函数,尝试生成下一个整数。在递归调用后,我们需要恢复ip
字符串的状态,以便尝试其他可能的解。 -
去除前导零:在循环中,需要特别处理前导零的情况。例如,如果以 0 开头的整数只能是 0,不能是 01 或 001 等。
-
结果返回:当递归搜索完成后,将得到的有效 IP 地址加入到结果向量
result
中,并最终返回结果。
这个算法的时间复杂度是 O(1),因为 IP 地址的长度是固定的。
参考代码:
#include <iostream>
#include <vector>
#include <string>
using namespace std;
vector<string> restoreIpAddresses(string s) {
vector<string> result;
string ip;
restoreIpAddressesDFS(s, 0, 0, ip, result);
return result;
}
void restoreIpAddressesDFS(const string& s, int start, int step, string ip, vector<string>& result) {
if (start == s.length() && step == 4) { // 如果已经遍历完整个字符串,并且已经找到了4个整数,则将结果加入到结果集中
result.push_back(ip);
return;
}
if (s.length() - start > (4 - step) * 3) return; // 剩余字符数太多,无法凑成一个IP地址
if (s.length() - start < (4 - step)) return; // 剩余字符数太少,无法凑成一个IP地址
int num = 0;
for (int i = start; i < start + 3; ++i) {
num = num * 10 + (s[i] - '0');
if (num <= 255) {
ip += s[i];
restoreIpAddressesDFS(s, i + 1, step + 1, ip + (step == 3 ? "" : "."), result);
}
if (num == 0) break; // 避免前导0的情况
}
}
int main() {
string s = "25525511135";
vector<string> result = restoreIpAddresses(s);
for (const auto& ip : result) {
cout << ip << endl;
}
return 0;
}