回溯算法之分割问题 leetcode分割回文串、复原ip地址

目录

131.分割回文串

93.复原ip地址


 131.分割回文串

题目:给你一个字符串 s,请你将s分割成一些子串,使每个子串都是 回文串 。返回 s 所有可能的分割方案。回文串 是正着读和反着读都一样的字符串。

思路:分割问题和组合问题有相似之处,一个是选数,一个是选分割线。

class Solution {
    List<List<String>> res=new ArrayList<>();
    List<String> path=new ArrayList<>();
    String s;
    public List<List<String>> partition(String s) {
        this.s=s;
        traceback(0);
        return res;
    }
    public void traceback(int start){
        //因为只有是回文字符串的时候才会回溯i+1,
        //所以start超过长度,说明一定找到了一组结果
        if(start>=s.length()){
            res.add(new ArrayList(path));
            return;
        }
        //!!标准的回溯找所有分割方法
        for(int i=start;i<s.length();i++){
            String substring=s.substring(start,i+1);
            if(isParlindrome(substring)){
                path.add(substring);
                traceback(i+1);
                path.remove(path.size()-1);
            }
        }
    }

    //判断字串是否是回文字符串
    public boolean isParlindrome(String s){
        int left=0,right=s.length()-1;
        while(left<right){
            if(s.charAt(left)!=s.charAt(right))return false;
            left++;
            right--;
        }
        return true;
    }
}
93.复原ip地址

题目:

思路:和上一个题一样,也是分割。有一些小点不同,还有一些写的时候的错误记录,都标到代码里面了。

class Solution {
    List<String> res=new ArrayList<>();
    StringBuilder sb=new StringBuilder();
    String s;
    public List<String> restoreIpAddresses(String s) {
        if(s.length()<4 || s.length()>12)return res;
        this.s=s;
        traceback(0,0);
        return res;
    }

    //分割次数相比上题有限制,所以多了一个参数n记录分割次数
    public void traceback(int start,int n){
        //!!!这里多一个n==4,是为了防止n<4的时候也返回结果。
        if(start>=s.length()&&n==4){
            res.add(sb.deleteCharAt(sb.length()-1).toString());
            sb.append('.');//!!!!
            //错误记录1
            //这个是为了防止回溯sb的时候,删除的个数确定,多删的补回来凑数
            //!!!!!
            return;
        }
        for(int i=start;i<s.length();i++){
            String substring=s.substring(start,i+1);
            //n<4,是分割次数过多就跳过
            if(isIP(substring)&&n<4){
                sb.append(substring);
                sb.append('.');
                traceback(i+1,n+1);
                for(int j=0;j<=substring.length();j++){
                    sb.deleteCharAt(sb.length()-1);
                }
            }
        }

    }
    public boolean isIP(String s){
        if(s.length()>3 || s.length()==0)return false;
        if(s.length()>1 && s.charAt(0)=='0')return false;
        //错误记录2
        //!!!!!这个一定是'0',不能是0
        if(Integer.parseInt(s)>255)return false;
        return true;
    }
}

卡哥的java代码 主要看最后,回溯时sb删除的那行


class Solution {
    List<String> result = new ArrayList<String>();
    StringBuilder stringBuilder = new StringBuilder();

    public List<String> restoreIpAddresses(String s) {
        restoreIpAddressesHandler(s, 0, 0);
        return result;
    }

    // number表示stringbuilder中ip段的数量
    public void restoreIpAddressesHandler(String s, int start, int number) {
        // 如果start等于s的长度并且ip段的数量是4,则加入结果集,并返回
        if (start == s.length() && number == 4) {
            result.add(stringBuilder.toString());
            return;
        }
        // 如果start等于s的长度但是ip段的数量不为4,或者ip段的数量为4但是start小于s的长度,则直接返回
        if (start == s.length() || number == 4) {
            return;
        }
        // 剪枝:ip段的长度最大是3,并且ip段处于[0,255]
        for (int i = start; i < s.length() && i - start < 3 && Integer.parseInt(s.substring(start, i + 1)) >= 0
             && Integer.parseInt(s.substring(start, i + 1)) <= 255; i++) {
            // 如果ip段的长度大于1,并且第一位为0的话,continue
            if (i + 1 - start > 1 && s.charAt(start) - '0' == 0) {
                continue;
            }
            stringBuilder.append(s.substring(start, i + 1));
            // 当stringBuilder里的网段数量小于3时,才会加点;如果等于3,说明已经有3段了,最后一段不需要再加点
            if (number < 3) {
                stringBuilder.append(".");
            }
            number++;
            restoreIpAddressesHandler(s, i + 1, number);
            number--;
            // 删除当前stringBuilder最后一个网段,注意考虑点的数量的问题
            stringBuilder.delete(start + number, i + number + 2);
        }
    }
}

关于回溯时sb删除之前增加的网段。

我是倒数一个一个删,并且最后一个后面也加了点,保证数量不出错。

卡哥后面的java代码使用delete函数,确定前后索引。但是仍然存在最后一个网段少点,删除数量不同的问题,他这个索引i+number+2在最后一个字段会超过字符长度。

但是他的代码没有报错是为什么?

点到stringbuilder的delete函数源码看来一下:

可以看到:delete函数的第二个参数如果超过了sb的长度并不会报错,而是会让end=count

  • 10
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值