day30【代码随想录】回溯之分割回文串、复原IP地址、子集


前言

1、分割回文串
2、复原IP地址
3、子集


一、分割回文串(力扣131)

给你一个字符串 s,请你将 s 分割成一些子串,使每个子串都是 回文串 。返回 s 所有可能的分割方案。

回文串 是正着读和反着读都一样的字符串。
在这里插入图片描述
思路:
关键在于[startIndex,i] 这个区间就是我们切割的子串【重点!!!】
startIndex就相当于是切割线!!!
在这里插入图片描述
整体步骤:
1、如何模拟切割线
2、递归如何终止
3、如何获取子串
4、判断回文

class Solution {
    List<List<String>> res = new ArrayList<>();
    LinkedList<String> paths = new LinkedList<>();
    public List<List<String>> partition(String s) {
        backtracking(s,0);
        return res;

    }
    public void backtracking(String s,int startIndex){
        if(startIndex==s.length()){
            res.add(new ArrayList<>(paths));
            return ;
        }
        for(int i=startIndex;i<s.length();i++){
            if(isPalinderome(s,startIndex,i)){
                String str = s.substring(startIndex,i+1);
                paths.add(str);
            }else{
                continue;
            }
            backtracking(s,i+1);
            paths.removeLast();//回溯
        }
    }
    public boolean isPalinderome(String s,int start,int end){
        for(int i=start,j=end;i<j;i++,j--){
            if(s.charAt(i)!=s.charAt(j)){
                return false;
            }
        }
        return true;
    }
}

在这里插入图片描述

二、复原IP地址(力扣93)

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

在这里插入图片描述
思路:
在这里插入图片描述
与切割回文串类似:
关键在于切割 切割出来的子串区间 [stratIndex,i] 以及一些字符串的拼接操作,增加"." 判断子串是否合法等等

结束判断:
1、“.”逗点数量已经==3时,需要判断最后一段截取的子串是否合法,如果合法,收集结果

字符串拼接:
1、如果当前截取的子串合法
2、拼接子串(加“.”)
3、递归 (细节:参数不再是i+1 而是i+2)
4、回溯(子串也要退回之前的状态 把“.”去掉)

判断子串是否合法:
1、两位数及以上时 第一位如果为0 不合法
2、包含除0-9以外的其他字符 不合法
3、数值大于255 不合法

class Solution {
    List<String> res = new ArrayList<>();
    public List<String> restoreIpAddresses(String s) {
        if(s.length()>12) return res;
        backtracking(s,0,0);
        return res;
    }
    public void backtracking(String s,int startIndex,int pointSum){ 
        if(pointSum==3){
            //判断最后一个部分是不是合法
            if(isValid(s,startIndex,s.length()-1)){//左闭右闭区间
                //加入结果集    
                res.add(s);
            }
            return ;
        }
        for(int i=startIndex;i<s.length();i++){
            //判断所截取子串是否合法
            if(isValid(s,startIndex,i)){
                s=s.substring(0,i+1)+"."+s.substring(i+1);
                //插入逗号
                pointSum++;
                backtracking(s,i+2,pointSum);
                pointSum--;
                //删除逗号
                s=s.substring(0,i+1)+s.substring(i+2);
            }else{
                continue;
            }
        }
    }
    public boolean isValid(String s,int start,int end){
        if(start>end){
            return false;
        }
        if(s.charAt(start)=='0'&& start!=end){
            return false;
        }
        int num=0;
        for(int i=start;i<=end;i++){
            if(s.charAt(i)>'9' || s.charAt(i)<'0'){
                return false;
            }
            num = num*10+(s.charAt(i)-'0');
            if(num>255)return false;
        }
        return true;
    }
}

在这里插入图片描述

三、子集(力扣78)

给你一个整数数组 nums ,数组中的元素 互不相同 。返回该数组所有可能的子集(幂集)。

解集 不能 包含重复的子集。你可以按 任意顺序 返回解集。

在这里插入图片描述
以示例中nums = [1,2,3]为例把求子集抽象为树型结构,如下:
在这里插入图片描述
求取子集问题,不需要任何剪枝!因为子集就是要遍历整棵树。
遍历这个树的时候,把所有节点都记录下来,就是要求的子集集合。

class Solution {
    List<List<Integer>> res = new ArrayList<>();
    LinkedList<Integer> paths = new LinkedList<>();
    public List<List<Integer>> subsets(int[] nums) {
        backtracking(nums,0);
        return res;
    }
    public void backtracking(int[] nums,int startIndex){
        res.add(new ArrayList<>(paths)); //遍历这棵树的时候,把所有结点记录下来
        if(startIndex==nums.length){
            return ;
        }
        for(int i=startIndex;i<nums.length;i++){
            paths.add(nums[i]);
            backtracking(nums,i+1);
            paths.removeLast();
        }
    }
}

在这里插入图片描述


总结

如果把 子集问题、组合问题、分割问题都抽象为一棵树的话,那么组合问题和分割问题都是收集树的叶子节点,而子集问题是找树的所有节点!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值