题目相关
题目链接
LeetCode中国,https://leetcode-cn.com/problems/restore-ip-addresses/。注意需要登录。
题目描述
给定一个只包含数字的字符串,复原它并返回所有可能的 IP 地址格式。
示例
输入: "25525511135"
输出: ["255.255.11.135", "255.255.111.35"]
题目分析
题意分析
给一个肯定合法的字符串,找出所有合法 IP 地址。
样例数据分析
我们肯定需要逐一遍历字符,看能否构成合法 IP 地址中的一个小节。我们知道 IP 地址要符合这个规定:
1、数据必须在 0 ~ 255 之间。
2、IP 地址最多只有 4 段。
因此,拿到一个字符后,我们的操作可以有以下三个:
1、如果是零,强制构成 IP 地址中的一个小节。
2、如果非零。我们有两个选择,选择一:自己构成 IP 地址中的一个小节;选择二:和其后若干个(1 或者 2)字符一起,只要不超过 255,构成 IP 地址中的一个小节。
下面我们根据样例输入 "25525511135",来模拟一下整个构造过程:
1、字符 2 单独构成一个小节,哪么可能 IP 为 "2.",继续搜索 "5525511135"。
2、字符 5 单独构成一个小节,哪么可能 IP 为 "2.5",继续搜索 "525511135"。
3、字符 5 单独构成一个小节,哪么可能 IP 为 "2.5.5",继续搜索 "25511135"。
4、字符 2 单独构成一个小节,哪么可能 IP 为 "2.5.5.2",继续搜索 "5511135"。
5、构造的 IP 地址完成,但是还有数据,则该 IP 不合法。
6、字符 2 和下一个字符 5 合作构成一个小节,哪么可能 IP 为 "2.5.5.25",继续搜索 "511135"。
7、构造的 IP 地址完成,但是还有数据,则该 IP 不合法。
8、字符 2 、下一个字符 5 和下一个字符 5 合作构成一个小节,哪么可能 IP 为 "2.5.5.255",继续搜索 "11135"。
9、构造的 IP 地址完成,但是还有数据,则该 IP 不合法。
10、字符 5 和下一个字符 2 合作构成一个小节,哪么可能 IP 为 "2.5.52",继续搜索 "25511135"。
11、字符 2 单独构成一个小节,哪么可能 IP 为 "2.5.52.2",继续搜索 "5511135"。
12、构造的 IP 地址完成,但是还有数据,则该 IP 不合法。
...,以此类推。整个构造出来的 IP 地址如下:
2.5.5.2
2.5.5.25
2.5.5.255
2.5.52.5
2.5.52.55
2.55.2.5
2.55.2.55
2.55.25.5
2.55.25.51
2.55.255.1
2.55.255.11
2.55.255.111
25.5.2.5
25.5.2.55
25.5.25.5
25.5.25.51
25.5.255.1
25.5.255.11
25.5.255.111
25.52.5.5
25.52.5.51
25.52.55.1
25.52.55.11
25.52.55.111
255.2.5.5
255.2.5.51
255.2.55.1
255.2.55.11
255.2.55.111
255.25.5.1
255.25.5.11
255.25.5.111
255.25.51.1
255.25.51.11
255.25.51.113
255.255.1.1
255.255.1.11
255.255.1.113
255.255.11.1
255.255.11.13
255.255.111.3
最终合法的 IP 地址只有 2 个。
算法思路
又是一个标准的 DFS 问题,LeetCode 定义的难度为中等。
搜索终止条件
1、当前搜索的位置达到输入字符串的长度。即 pos>=s.length()。
2、已经构造出了 4 个小节的 IP 地址。
搜索函数参数
1、第一个参数:s字符串
2、第二个参数:path当前搜索结果字符串
3、第三个参数:k搜索出几个小节
4、第四个参数:pos当前位置
因此 dfs() 函数的原型如下:
void dfs(string &s, string path, int k, int pos);
开始调用方式
string path;
dfs(s, path, 0, 0);
回溯
不需要。
算法步骤
1、从字符串 s 的第 0 个字符出发开始搜索。
2、如果当前 pos 位置字符为 0,则构成一个 IP 地址的小节。继续搜索下一个字符。
3、当前 pos 位置字符不为零。考虑到每个 IP 的小节不能操作 256,也就意味着最多和后面 2 个字符一起构成。那么我们需要搜索这 3 中可能。第一种:自己独立构造;第二种:和后面的一个字符一起构造;第三种:和后面的两个字符一起构造。
AC 参考代码
class Solution {
public:
vector<string> ans;
vector<string> restoreIpAddresses(string s) {
string path;
dfs(s, path, 0, 0);
return ans;
}
/*
第一个参数:s字符串
第二个参数:path当前搜索结果字符串
第三个参数:k搜索出几个小节
第四个参数:pos当前位置
*/
void dfs(string &s, string path, int k, int pos) {
if (pos>=s.length()) {
//操作长度了
if (k>=4) {
ans.push_back(path.substr(1));
}
return;
}
if (k>=4) {
//不合法的搜索
cout << path.substr(1) << endl;
return;
}
if ('0'==s[pos]) {
//当前是0
dfs(s, path+".0", k+1, pos+1);
} else {
//不是零
int t=0;
for (int i=pos; i<s.length(); i++) {
t = t*10+(s[i]-'0');
if (t<256) {
//看能否构成IP
dfs(s, path+"."+to_string(t), k+1, i+1);
} else {
break;
}
}
}
}
};