代码随想录算法训练营第27天|● 93.复原IP地址 ● 78.子集 ● 90.子集II

93.复原IP地址

看完题后的思路

  1. 典型分割问题
  2. lue
  3. 剪枝条件
    sub: 1) 不是一位首字母为0 2)大于三位 3)介于0-255之间
    4) 当已分割得到3个时,第四个直接从startIndex到末尾就行

代码

  ArrayList<String> slist = new ArrayList<>();
    ArrayList<String> restoreIpAddressesPath = new ArrayList<>();

    public List<String> restoreIpAddresses(String s) {
        restoreIpAddressesBT(s,0);
        return slist;
    }
    public void restoreIpAddressesBT(String s,int startIndex) {
        if (startIndex==s.length()){
            if (restoreIpAddressesPath.size()==4){
                StringBuilder sb = new StringBuilder();
                for (String s1 : restoreIpAddressesPath) {
                    sb.append(s1+".");
                }
                sb.delete(sb.length()-1,sb.length());
                slist.add(sb.toString());
            }
            return;
        }

        for (int i = startIndex; i <s.length() ; i++) {
            String substring = s.substring(startIndex, i + 1);
            // 剪枝
            // 如果已经有3个了,直接看剩下的能不能凑成第四个就行
            if (restoreIpAddressesPath.size()==3&&valIsValid(s.substring(i+1))==-1){
                return;  // 本层全不能用
            }
            // 其余情况
            if (valIsValid(substring)==-1){
                continue;
            }
            restoreIpAddressesPath.add(substring);
           restoreIpAddressesBT(s,i+1);
            restoreIpAddressesPath.remove(restoreIpAddressesPath.size()-1);
        }
    }
    public int valIsValid(String str){
        if (str==null){
            return -1;
        }
        if (str.length()>1&&str.charAt(0)=='0'){
            return -1;
        }
        if (str.length()>3){
            return -1;
        }
        int val=0;
        for (int i = 0; i < str.length(); i++) {
            val=val*10+(str.charAt(i)-'0');
        }
        if (val>255){
            return -1;
        }
        return val;
    }

复杂度

在这里插入图片描述

收获

  1. 分割常用的递归出口
    (1)startIndex==数组长度
    缺点: 如果是分割有段数要求,例如ip,可能分割很多段后才到递归出口,1.1.1.1.1.1.1 再判断,白白浪费性能。
    改进:当已经分割三段时,第四段直接判断,这样可以剪掉部分,但是最后还是会一个一个试
   public void restoreIpAddressesBT(String s,int startIndex) {
        if (startIndex==s.length()){
            if (restoreIpAddressesPath.size()==4){
                StringBuilder sb = new StringBuilder();
                for (String s1 : restoreIpAddressesPath) {
                    sb.append(s1+".");
                }
                sb.delete(sb.length()-1,sb.length());
                slist.add(sb.toString());
            }
            return;
        }

        for (int i = startIndex; i <s.length() ; i++) {
            String substring = s.substring(startIndex, i + 1);
            // 剪枝
               // 如果已经有3个了,直接看剩下的能不能凑成第四个就行
            if (restoreIpAddressesPath.size()==3&&valIsValid(s.substring(startIndex))==-1){
                return;  // 本层全不能用
            }
            if (valIsValid(substring)==-1){
                continue;
            }
            restoreIpAddressesPath.add(substring);
           restoreIpAddressesBT(s,i+1);
            restoreIpAddressesPath.remove(restoreIpAddressesPath.size()-1);
        }
    }

(2)如果有段数要求,直接用段数作为剪枝条件

  if (restoreIpAddressesPath.size()==4){
            if (startIndex==s.length()){
                StringBuilder sb = new StringBuilder();
                for (String s1 : restoreIpAddressesPath) {
                    sb.append(s1+".");
                }
                sb.delete(sb.length()-1,sb.length());
                slist.add(sb.toString());
            }
            return;
        }

在这里插入图片描述
这样只要到段数,就会判断,不会再 1.1.1.1.1.1.1这样分割
2. 三刷敲一遍

78.子集

看完题后的思路

在这里插入图片描述
一.0. 本题本质上是个组合问题,[]的处理可以在递归出口前将path加入,即向上提一层

  1. void f(【】,startIndex)
  2. 不用递归终止,用循环终止即可
  3. 递归
    res.add(path);
    递归终止
    循环引擎
    二. 为什么递归到最后,path为[]? 回溯删除的是自己,还是本节点?
    在这里插入图片描述

代码

class Solution {
       List<List<Integer>> ires = new ArrayList<>();
        ArrayList<Integer> ipath = new ArrayList<>();
 public List<List<Integer>> subsets(int[] nums) {
        subsetsBT(nums,0);
        System.out.println(ipath);
        return ires;
    }
    public void subsetsBT(int[] nums,int startIndex) {
        // 找所有从根节点的子路径,为处理空置,先加入
       ires.add(new ArrayList<>(ipath));

        // 递归终止条件  直接使用循环终止

        // 循环引擎
        for (; startIndex <nums.length ; startIndex++) {
            // 剪枝 无

            //三件套
            ipath.add(nums[startIndex]);
            subsetsBT(nums,startIndex+1);
            ipath.remove(ipath.size()-1); //  删除的是startIndex
        }
    }
}

复杂度

在这里插入图片描述

收获

  1. 三刷大脑过一遍
  2. 组合问题之子集问题,找到所有从根节点出发的子路径,包含【】

90.子集II

看完题后的思路

  1. 基本子集+横向去重

代码

class Solution {
       List<List<Integer>> ires = new ArrayList<>();
        ArrayList<Integer> ipath = new ArrayList<>();
 // 90. 子集 II
    public List<List<Integer>> subsetsWithDup(int[] nums) {
        boolean[] using = new boolean[nums.length];
        Arrays.sort(nums);
        subsetsWithDupBT(nums,using,0);
        return ires;
    }

    public void subsetsWithDupBT(int[] nums,boolean[] using,int startIndex) {
        ires.add(new ArrayList<>(ipath));
        
        // 终止 无

        // 循环引擎
        for (int i = startIndex; i <nums.length ; i++) {
            // 剪枝
            if (i!=0&&nums[i]==nums[i-1]&&!using[i-1]){
                continue;
            }
            
          
            //三件套
            using[i]=true;
            ipath.add(nums[i]);
            subsetsWithDupBT(nums,using,i+1);
            ipath.remove(ipath.size()-1); //  删除的是startIndex
            using[i]=false;
        }
    }

}

复杂度

在这里插入图片描述

收获

三刷过

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

弈师亦友

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值