LeeCode 复原IP地址

92 阅读3分钟

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开头等等。希望这篇文章能够对大家在做类似问题时提供一些帮助。