93. 复原 IP 地址-全排列

232 篇文章 0 订阅

一、题目描述

有效 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 = "101023"
输出:["1.0.10.23","1.0.102.3","10.1.0.23","10.10.2.3","101.0.2.3"]

二、解题

回溯

这题就是有不少判断条件,首先是前导0的判定,出现了0,则直接进入回溯,还有ip地址的大小在0-255之间。

class Solution {
    static final int SEG_COUNT = 4;
    List<String> res = new ArrayList<String>();
    int[] segments = new int[SEG_COUNT];

    public List<String> restoreIpAddresses(String s) {
        segments = new int[SEG_COUNT];
        //开始回溯 从0下标开始遍历
        dfs(s,0,0);
        return res;
        
    }

    public void dfs(String s, int segId, int segStart) {
        //首先写跳出终止条件
        //如果到达了四段
        if(segId == SEG_COUNT){
            //如果遍历完了字符串
            if(segStart == s.length()){
                //拼接四段
                StringBuilder sb = new StringBuilder();
                for(int i = 0;i<SEG_COUNT;i++){
                    sb.append(segments[i]);
                    //添加 .
                    if(i != SEG_COUNT - 1){
                        sb.append('.');
                    }
                }
                res.add(sb.toString());
            }
            return ; 
        }
        //如果没有找到四段地址就已经遍历完了字符串 提前回溯
        if(segStart == s.length()){
            return ;
        }
        //前导0判别
        if(s.charAt(segStart) == '0'){
            segments[segId] = 0;
            dfs(s,segId+1,segStart+1);
        }
        //一般情况
        int addr = 0;
        for(int end = segStart;end<s.length();end++){
            addr = addr * 10 +(s.charAt(end) - '0');
            if(addr>0 && addr <= 255){
                segments[segId] = addr;
                dfs(s,segId+1,end+1);
            }else{
                break;
            }
        }        
    }
}

全排列

class Solution {
    public List<String> restoreIpAddresses(String s) {
        List<String> res = new ArrayList<>();
        List<String> path = new ArrayList<>();
        if(s == null){
            return res;
        }
        dfs(s,res,path,0);
        return res;
    }

    //DFS
    public void dfs(String s,List<String> res,List<String> path,int start){
        //终止条件
        if(path.size() == 4){
            if(start == s.length()){
                //添加数据
                StringBuilder sb = new StringBuilder();
                for(int i = 0;i<path.size();i++){
                    sb.append(path.get(i));
                    if(i != 3){
                        sb.append('.');
                    }
                }
                res.add(sb.toString());
                return ;
            }else{
                return;
            }
        }

        //一般情况 分割字符串,然后判断这个字符串是否是有效的ip字段
        for(int end = start;end<s.length();end++){
            if(isValidIp(s,start,end)){
                //如果是有效的ip字段
                // 添加字段
                path.add(s.substring(start,end+1));
                dfs(s,res,path,end+1);
                path.remove(path.size()-1);
            }
        }
    }

    public boolean isValidIp(String s,int left,int right){
        if(left>right){
            return false;
        }
        //ip字段长度不超过三位数
        if(right - left > 3){
            return false;
        }
        //前导0
        if(s.charAt(left) == '0' && left != right){
            return false;
        }
        // 判断这个字符串[left, right]是不是满足0, 255的范围
        int sum = Integer.valueOf(s.substring(left, right + 1));
        return sum >= 0 && sum <= 255 ? true : false;
    }
}
class Solution {
    List<String> result = new ArrayList();
    List<String> ipString = new ArrayList();
    public List<String> restoreIpAddresses(String s) {
        dfs(s,0);
        return result;
    }

    public void dfs(String source,int index){
        if(ipString.size()==4){
            if(index == source.length()){
                StringBuilder sb = new StringBuilder();
                for(int i=0;i<ipString.size();i++){
                    sb.append(ipString.get(i));
                    if(i!=ipString.size()-1){
                        sb.append(".");
                    }
                }
                result.add(sb.toString());
                return;
            } else{
                return;
            }
        }

        for(int i = index;i<source.length();i++){
            if(isIP(source,index,i)){
                ipString.add(source.substring(index,i+1));
                dfs(source,i+1);
                ipString.remove(ipString.size()-1);
            }        
        }
    }

    public boolean isIP(String s,int left,int right){
        

      if (left > right) {
            return false;
        }
          if (right - left > 3) {
            return false;
        }
        if (s.charAt(left) == '0' && left != right) {
            return false;
        }
        // 判断这个字符串[left, right]是不是满足0, 255的范围
        int ans = Integer.valueOf(s.substring(left, right + 1));
        
        return ans >= 0 && ans <= 255 ? true : false;
    }
}
class Solution {
    List<String> res = new ArrayList<>();
    List<String> path = new ArrayList<>();
    public List<String> restoreIpAddresses(String s) {
        //这里就是对字符串的预处理,但是对于测试用例来说我觉得用处不大,毕竟不会蠢到用13位数字让你分割
        if(s.length()<4 || s.length()>12){
            return res;
        }
        //这里就是套用最经典的回溯模板了,相比于分割字符串只加入分割线一个参数以外,这里还需要添加额外的层数参数level
        //因为合法的IP地址只有四段,我们不能无限对其进行分割
        backtracking(s,0,0);
        return res;
    }

    // 判断分割出来的每一段字符串是否是合法的IP地址
    boolean isValidIp(String s){
        //判断其是否含有前导0
        if(s.charAt(0)=='0' && s.length()>1){
            return false;
        }
        //长度为4就直接舍弃,加上这一步是为了后面parseInt做准备,防止超过了Integer可以表示的整数范围
        if(s.length()>3){
            return false;
        }
        //将字符转为int判断是否大于255,因为题目明确说了只由数字组成,所以这里没有对非数字的字符进行判断
        if(Integer.parseInt(s)>255){
            return false;
        }
        return true;
    }

    void backtracking(String s,int splitIndex,int level){
        //递归终止条件,分割的四个字符串都是合法的IP地址
        if(level==4){
            //在代码的最后再利用join函数加上“.”,构造IP地址的表示形式
            res.add(String.join(".",path));
            return;
        }
        for(int i=splitIndex;i<s.length();i++){
            //每一次分割之后,对剩余字符长度是否合理进行判断,剪枝操作,优化运行速度
            if((s.length()-i-1) > 3*(3-level)){
                continue;
            }
            //如果分割的字符串不是合理的IP地址,跳过
            if(! isValidIp(s.substring(splitIndex,i+1))){
                continue;
            }
            //把合法的IP地址段加入path存储
            path.add(s.substring(splitIndex,i+1));
            //每次把分割线往后移一位,且段数level+1
            backtracking(s,i+1,level+1);
            //进行回溯操作
            path.remove(path.size()-1);
        }
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值