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

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

93.复原IP地址

有效 IP 地址 正好由四个整数(每个整数位于 0255 之间组成,且不能含有前导 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"]

题解:分割问题。需要注意的是,分割完需要再字符串中加上点号,并且还要判断每段字符的合法性(单独写一个函数判断)。在回溯的时候,因为添加了一个点号,所以回溯的起始位置是i+2,算上点号占的一个字符。在指定位置添加点号的StringBuilder的方法是.insert(添加位置,添加内容)

代码

class Solution {
    List<String> res=new ArrayList<>();
    public List<String> restoreIpAddresses(String s) {
        StringBuilder str=new StringBuilder(s);
        backtracking(str,0,0);
        return res;
    }
    public void backtracking(StringBuilder s,int startIndex,int point){
        //终止条件
        //遍历完字符串,并且用三个点将IP分为4段
        if(point==3){
            if(isValid(s,startIndex,s.length()-1)){
                res.add(s.toString());
            }
            return;
        }
        //单层逻辑
        for(int i=startIndex;i<s.length();i++){
            if(isValid(s,startIndex,i)){
                //不能用append(i),它会将点号从开始添加到末尾
                s.insert(i+1,'.');
                backtracking(s,i+2,point+1);
                s.deleteCharAt(i+1);
            }else{
                break;
            }
        }
    }
    //判断是不是合法的IP(每个IP段的值不能为0,并且不能超过255)
    public boolean isValid(StringBuilder s,int start,int end){
        if(start>end) return false;
        //ip段不能为0
        if(start!=end && s.charAt(start)=='0') return false;
        int sum=0;
        for(int i=start;i<=end;i++){
            int digit=s.charAt(i)-'0';
            sum=sum*10+digit;
            if(sum>255) 
                return false;
        }
        return true;
    }
}

78.子集

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

子集

(幂集)。

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

示例 1:

输入:nums = [1,2,3]
输出:[[],[1],[2],[1,2],[3],[1,3],[2,3],[1,2,3]]

题解:和组合问题的逻辑是差不多的,区别在于:组合是在叶子节点收获结果,也就是叶子节点是结果,终止条件可以直接判断有没有到叶子结点,并且在终止条件中收获结果集。可是子集是路径上的每一个搜索点都是结果,也就是树层也是结果,那么终止条件该怎么写呢?结果集又该怎么收获呢?

子集问题不在终止条件收获结果集,终止条件就是一条路径已经搜索完毕

结果集在for循环中收获,每一次回溯到for循环,传入的都是这条路径保存到的当前节点,所以直接将这个path加入到res结果集

代码

class Solution {
    List<List<Integer>> res=new ArrayList<>();
    List<Integer> path=new ArrayList<>();
    public List<List<Integer>> subsets(int[] nums) {
        backtracking(nums,0);
        return res;
    }
    public void backtracking(int nums[],int startIndex){
        res.add(new ArrayList<>(path));
        //终止条件 一条路径搜索完
        if(startIndex==nums.length){
            return;
        }
        for(int i=startIndex;i<nums.length;i++){
            path.add(nums[i]);
            backtracking(nums,i+1);
            path.removeLast();
        }
    }
}

90.子集II

题解:组合和集合结合的问题。需要考虑组合中元素在同一个子集中可以重复出现,但是不能出现重复的子集,所以需要用used数字记录每个数字是否已经被横向遍历过(需要给原数组排序),然后看数组当前值和前一个值是否相等,并判断前一个值是否被遍历过。

子集则是收集结果的时候注意树层的也是结果,终止条件和收集结果的地方需要注意。

代码

class Solution {
    List<List<Integer>> res=new ArrayList<>();
    List<Integer> path=new ArrayList<>();
    boolean [] used;
    public List<List<Integer>> subsetsWithDup(int[] nums) {
        used=new boolean[nums.length];
        Arrays.fill(used,false);
        //给数组排序
        Arrays.sort(nums);
        backtracking(nums,0);
        return res;
    }
    //回溯 用used数组记录相同元素有没有遍历过
    public void backtracking(int[] nums,int startIndex){
        //子集,收获结果在回溯开始
        res.add(new ArrayList<>(path));

        //终止条件
        if(startIndex==nums.length) return;

        //for循环
        for(int i=startIndex;i<nums.length;i++){
            if(i>0 && nums[i]==nums[i-1] && !used[i-1]) continue;
            path.add(nums[i]);
            used[i]=true;
            backtracking(nums,i+1);
            used[i]=false;
            path.removeLast();
        }
    }
}
  • 7
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值