LeeCode 复原IP地址
复原IP地址是一道经典的LeetCode题目,它的主要目的是将一个包含数字的字符转换成形如 "255.255.255.255" 的IP地址格式。在此篇文章中,我们会深入学习这个题目以及可能出现的一些问题。
LeetCode 复原 IP 地址题目描述
给定一个仅包含数字的字符串,复原它并返回所有可能的 IP 地址格式。
示例: 输入: "25525511135" 输出: ["255.255.11.135", "255.255.111.35"]
示例 2: 输入: "0000" 输出: ["0.0.0.0"]
示例 3: 输入: "1111" 输出: ["1.1.1.1"]
示例 4: 输入: "010010" 输出: ["0.10.0.10","0.100.1.0"]
解题思路
定义递归函数 backtrack(track, str, start),其中:
- track 为存储每一轮已经形成的 IP 地址
- str 为原字符串
- start 为当前 IP 地址中数值的起始下标
递归终止条件为:
- 字符串已经处理完毕,且 track 中已经存储了 4 段 IP 地址。
- 字符串已经处理完毕,但 track 中未能存储 4 段 IP 地址。
在递归过程中,最重要的判断是每次判断当前起始下标 start 是否已经到了字符串的末尾。如果到了末尾,而且 track 中已经存储了 4 段 IP 地址,直接将当前路径放入结果列表中。否则,终止递归过程。
对于非递归的情况,如果当前IP地址的起始数字不能为0,则可以以一位、两位、三位数为一个IP地址的一段,以此递归下去。
Java代码实现
public class RestoreIP { public List restoreIpAddresses(String s) { List res = new ArrayList<>(); if (s == null || s.length() < 4 || s.length() > 12) { return res; } backtrack(res, new ArrayList<>(), s, 0); return res; }
private void backtrack(List<String> res, List<String> track, String s, int start) {
if (track.size() == 4 && start == s.length()) {
res.add(String.join(".", track));
return;
}
if (track.size() == 4 || start == s.length()) {
return;
}
for (int len = 1; len <= 3 && start + len <= s.length(); len++) {
String segment = s.substring(start, start + len);
if ((segment.startsWith("0") && segment.length() > 1) ||
(len == 3 && Integer.parseInt(segment) >= 256)) {
continue;
}
track.add(segment);
backtrack(res, track, s, start + len);
track.remove(track.size() - 1);
}
}
}
总结
此题思路比较简单,但是需要注意一些细节问题。同时,在实际应用中,会遇到各种形式的IP地址,我们需要根据实际情况进行灵活处理。
优化
除了逐个枚举和回溯的解法外,还有一种基于 DFS 深度优先搜索的解法。下面我们来详细介绍一下这种解法。
DFS 深度优先搜索解法
思路:
DFS 解法是从左向右扫描数字串找 IP 地址,每碰到一个合法的 IP 地址就加入结果集。我们从当前位置提取一段数字,尝试把这段数字加入地址中。如果当前的 IP 地址还没有 4 个段(属于合法情况),就继续进行搜索,否则如果字符串已经被处理完,那么这就是一组合法的解,加入合法解列表。
需要注意的是,我们对每个 IP 地址段进行判断时,一旦知道这个段不能加入现有 IP 地址中,就可以不必继续考虑下去。例如,如果碰到一个 0 开头的数字,那么此段数字就只能是0,不能是01或者02。
Java 代码实现:
public class RestoreIPAddress2 { public List restoreIpAddresses(String s) { List ans = new ArrayList<>(); dfs(ans, s, new StringBuilder(), 0, 1); return ans; }
private void dfs(List<String> ans, String s, StringBuilder ip, int idx, int count) {
if (count == 5) {
if (idx == s.length()) ans.add(ip.toString());
return;
}
if (idx == s.length()) return;
if (ip.length() != 0) ip.append(".");
dfs(ans, s, new StringBuilder(ip).append(s.charAt(idx)), idx + 1, count + 1);
if (s.charAt(idx) != '0' && idx + 1 < s.length())
dfs(ans, s, new StringBuilder(ip).append(s.substring(idx, idx + 2)), idx + 2, count + 1);
if (idx + 2 < s.length() && isValid(s, idx, idx + 3))
dfs(ans, s, new StringBuilder(ip).append(s.substring(idx, idx + 3)), idx + 3, count + 1);
ip.setLength(ip.lastIndexOf(".") + 1);
}
private boolean isValid(String s, int start, int end) {
String sub = s.substring(start, end);
if (sub.charAt(0) == '0') return false;
int num = Integer.parseInt(sub);
return num >= 0 && num <= 255;
}
}
总结
本文介绍了LeetCode的复原IP地址题目,分别介绍了两种递归和 DFS 解法。需要注意的是,无论是哪种解法,都需要注意特殊情况的处理,例如字符串过短或过长;数字以0开头等等。希望这篇文章能够对大家在做类似问题时提供一些帮助。