算法思路汇总:93.复原 IP 地址

267 阅读2分钟

93. 复原 IP 地址

「这是我参与2022首次更文挑战的第23天,活动详情查看:2022首次更文挑战」。

难度:mid 来源:力扣(LeetCode)

有效 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 中的任何数字。你可以按 任何 顺序返回答案。

示例 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"]

提示

  1. 0 <= s.length <= 20
  2. s 仅由数字组成

思路:

该题目也属于字符串分割问题,最好可以先看一下lc131:分割回文串;大体思路需要两个变量:

index实现字符串的分割,pointNum实现判断点的数量;

通过上述两个变量可以实现结束条件:

  1. 判断逗号的数量
  2. 判断时候满足ip地址的要求

对于第一个要求,只需要判断pointNum是否等3,如果等于3则判断最后一组是否满足要求,满足要求则添加入结果中,否则break;

根据题目知第二个要求为:

  1. 每个整数不能以0开头
  2. 每个整数范围0-255
  3. 存在非整数是非法的

由上得:

//如果小数点等于三,表示前三个满足提议
if(pointNum == 3){
    //判断最后一组是否满足要求
    if(isValid(s,index,s.length()-1)){
        res.add(s);
        return;
    }
}
Boolean isValid(String s,int start,int end){
    if(start > end) return false;
    // 1. 每个整数不能以0开头
    // 2. 每个整数范围0-255
    // 3. 存在非整数是非法的
    int num = 0;
    if(s.charAt(start) == '0' && start != end) return false;
    for(int i = start; i <= end; i++){
        if(s.charAt(i) < '0' || s.charAt(i) > '9') return false;
        num = num * 10 + (s.charAt(i) - '0');
        if (num > 255) { // 如果⼤于255了不合法
            return false;
        }
    }
    return true;
}

然后进行字符串的横向遍历,如果有满足条件的(该题目在原来的字符串上进行修改):

  1. 在满足条件的位置上添加上逗号
  2. pointNum++
  3. 递归
  4. pointNum--
  5. 回溯
for(int i = index; i < s.length(); i++){
            //如果满足条件
             if (isValid(s, index, i)) {
                //找到的位置进行分割,中间加入点
                 s = s.substring(0,i+1) + "." +s.substring(i+1);
                 pointNum++;
                 backTrack(s,i+2,pointNum);
                 pointNum--;
                // i+1的位置为点----5  .  5
                //-----------------i i+1 i+2
                s = s.substring(0,i+1)+s.substring(i+2);
             }else{
                 break;
             }
        }

简单的优化:根据题目可以需要满足IP要求。

字符串的长度小于 4 或者大于 12 ,一定不能拼凑出合法的 ip 地址

小于4拼不出0.0.0.0,最多255.255.255.255也就是在原字符串长度12,其他都不符合

完整代码:

class Solution {
    List<String> res = new ArrayList<>();
    public List<String> restoreIpAddresses(String s) {
        //index: 切割点,pointNum:小数点
        // 字符串的长度小于 4 或者大于 12 ,一定不能拼凑出合法的 ip 地址
        //小于4拼不出0.0.0.0,最多255.255.255.255也就是长度12,其他都不符合
        if(s.length() < 4 || s.length() > 12) return res;
        backTrack(s,0,0);
        return res;
    }
    void backTrack(String s,int index,int pointNum){
        //如果小数点等于三,表示前三个满足提议
        if(pointNum == 3){
            //判断最后一组是否满足要求
            if(isValid(s,index,s.length()-1)){
                res.add(s);
                return;
            }
        }
        for(int i = index; i < s.length(); i++){
            //如果满足条件
             if (isValid(s, index, i)) {
                //找到的位置进行分割,中间加入点
                 s = s.substring(0,i+1) + "." +s.substring(i+1);
                 pointNum++;
                 backTrack(s,i+2,pointNum);
                 pointNum--;
                // i+1的位置为点----5  .  5
                //-----------------i i+1 i+2
                s = s.substring(0,i+1)+s.substring(i+2);
             }else{
                 break;
             }
        }
    }
    Boolean isValid(String s,int start,int end){
        if(start > end) return false;
        // 1. 每个整数不能以0开头
        // 2. 每个整数范围0-255
        // 3. 存在非整数是非法的
        int num = 0;
        if(s.charAt(start) == '0' && start != end) return false;
        for(int i = start; i <= end; i++){
            if(s.charAt(i) < '0' || s.charAt(i) > '9') return false;
            num = num * 10 + (s.charAt(i) - '0');
            if (num > 255) { // 如果⼤于255了不合法
                return false;
            }
        }
        return true;
    }
}

参考文献:

代码随想录