Skip to content

Latest commit

 

History

History
113 lines (99 loc) · 3.94 KB

93.复原IP地址.md

File metadata and controls

113 lines (99 loc) · 3.94 KB

93.复原IP地址

题目

给定一个只包含数字的字符串,复原它并返回所有可能的 IP 地址格式。

有效的 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 地址。

 

示例 1:
输入:s = "25525511135"
输出:["255.255.11.135","255.255.111.35"]

示例 2:
输入:s = "0000"
输出:["0.0.0.0"]

示例 3:
输入:s = "1111"
输出:["1.1.1.1"]

示例 4:
输入:s = "010010"
输出:["0.10.0.10","0.100.1.0"]

示例 5:
输入:s = "101023"
输出:["1.0.10.23","1.0.102.3","10.1.0.23","10.10.2.3","101.0.2.3"]

方法(暴力法)

public List<String> restoreIpAddresses(String s) {
    List<String> res = new ArrayList<String>();
    if(s == null || s.length() == 0 || s.length() > 12)
        return res;
    StringBuffer ip = new StringBuffer();
    for(int a = 1; a < 4; a++){
        for(int b = a + 1; b < a + 4; b++){
            for(int c = b + 1; c < s.length(); c++){
                int n1 = Integer.parseInt(s.substring(0, a));
                int n2 = Integer.parseInt(s.substring(a, b));
                int n3 = Integer.parseInt(s.substring(b, c));
                int n4 = Integer.parseInt(s.substring(c, s.length()));
                if(n1 <= 255 && n2 <= 255 && n3 <= 255 && n4 <= 255)
                    ip.append(n1).append(".").append(n2).append(".").append(n3).append(".").append(n4);
                if(ip.length() == s.length() + 3)
                    res.add(ip.toString());
                ip.delete(0, ip.length());
            }
        }
    }
    return res;
}

方法(回溯法)

  • 递归终止条件:当遍历完S的每一位时,如果已经切分好了IP地址的四段,那么将切分好的IP地址加入结果。否则直接返回。
  • 选择:在每一个位置都有三种选择:截取当前位置和后1位作为IP地址中的一段、截取当前位置和后2位作为IP地址中的一段、截取当前位置和后3位作为IP地址中的一段
  • 路径:用一个列表记录分割成的IP地址的每一段
List<String> res;
String s;
public List<String> restoreIpAddresses(String s) {
    this.s = s;
    res = new LinkedList<>();
    if(s.length() > 12 || s.length() < 4)
        return res;
    List<String> path = new LinkedList<>();
    backtrack(0, 0, path);
    return res;
}
//start代表从哪个位置开始回溯
//cutNum代表已经分割了IP地址中的多少段(最多为4段)
//path记录当前分割成的IP地址中的每一段
public void backtrack(int start, int cutNum, List<String> path){
    //终止条件
    if(start == s.length()){
        if(cutNum == 4)
            res.add(String.join(".", path));
    }
    //在每一个结点处可以选择截取的方法只有 3 种:向后截 1 位、截 2 位、截 3 位
    for(int i = start; i < start + 3; i++){
        //一下两个if判断为剪枝条件
        if(i > s.length())
            break;
        if((4 - cutNum) * 3 < s.length() - i)
            continue;
        if(validIPsegment(start, i)){
            String temp = s.substring(start, i + 1);
            path.add(temp);
            backtrack(i + 1, cutNum + 1, path);
            path.remove(path.size() - 1);
        }
    }
}
//判断S中从left到right中间的部分是否是合法的IP地址段
public boolean validIPsegment(int left, int right){
    if((left < right && s.charAt(left) == '0') || right >= s.length())
        return false;
    int count = 0;
    for(int i = left; i <= right; i++){
        count = count * 10 + (s.charAt(i) - '0');
    }
    return count >= 0 && count <= 255;
}

参考