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

目录

93.复原IP地址

78.子集

90.子集II


93.复原IP地址

本期本来是很有难度的,不过 大家做完 分割回文串 之后,本题就容易很多了

题目链接/文章讲解:代码随想录

视频讲解:回溯算法如何分割字符串并判断是合法IP?| LeetCode:93.复原IP地址_哔哩哔哩_bilibili

题解思路:

本题看完卡哥视频思路还是清楚的,里面的有些细节一定要注意,具体的实现方式和代码见注释,说的很详细了,搭配卡哥的视频教程就是说一整个香住了!!!

class Solution {

    List<String> result = new ArrayList<>();
    int pointSum = 0;

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

    public void backtracking(String s, int startIndex){
        if(pointSum == 3){
            if(isValid(s, startIndex, s.length() - 1)){
                result.add(s); 
            }
            return;
        }
        //substring(start,end):左闭右开切割子字符串的
        for(int i = startIndex; i < s.length(); i++){ //for循环横向遍历,这不需要控制的,每轮结束后直接会到下一轮
            if(isValid(s, startIndex, i)){
                s = s.substring(0, i + 1) + "." + s.substring(i +1); //踩过的坑1------------字符串的拼接!在切割的字符串的两端中间添加一个逗号,这里一定是s.substring(0, i + 1)从0开始切割,切割判断得到的字符串一定是整个字符串的长度加上逗号的个数,不能是从startIndex开始索引的
                pointSum++;
                backtracking(s, i + 2); //递归纵向遍历,需要控制的,也是回溯算法的关键,本质就是理解递归三部曲就行!!!如果是有效的整数,则在此轮中继续进行递归,每轮递归的终止条件就是当pointSUm == 3 的时候一定会终止,如果不符合就不添加到结果集里面,如果符合就添加到结果集中,然后开始回溯,回溯结束就是进行下一轮的递归操作
                pointSum--;
                s = s.substring(0, i + 1) + s.substring(i + 2); //踩过的坑2------------------回溯删掉逗号,继续往后判断,这里是s.substring(0, i + 1)从0开始切割,不能把之前符合的逗号删掉,只能删除刚添加的逗号,这才是真正的回溯算法
            }else{
                break; //切割的子字符串不是一个有效的整数,那么就没有必要再尝试更大的子字符串了,因此直接停止循环即可
            }
        }
    }
    
    //isValid(s, startIndex, i):有效字符串是左闭右闭的区间
    public boolean isValid(String s, int start, int end){
        //剪枝操作
        if(start > end) return false;
        //判断是否有效主要是两点
        //第一点:切割的字符串开头不能是0
        if(s.charAt(start) == '0' && start != end) return false;
        //第二点:字符串的数组小于等于255
        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.子集

子集问题,就是收集树形结构中,每一个节点的结果。 整体代码其实和 回溯模板都是差不多的。

题目链接/文章讲解:代码随想录

视频讲解:回溯算法解决子集问题,树上节点都是目标集和! | LeetCode:78.子集_哔哩哔哩_bilibili

题解思路:

算是很常规的一道题,没看题解自己写出来的,写了这么多道题还是有肌肉记忆的!!!先把树形结构画出来代码就能写出来,然后和之前的回溯算法题目差别在于:之前都是遇到叶子节点的时候才收集结果,而本题是每递归一次就要收集结果。

class Solution {
    LinkedList<Integer> path = new LinkedList<>();
    List<List<Integer>> result = new ArrayList<>();

    public List<List<Integer>> subsets(int[] nums) {
        backtracking(nums,0);
        return result;
    }

    public void backtracking(int[] nums, int startIndex){
        result.add(new LinkedList<Integer>(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

大家之前做了 40.组合总和II 和 78.子集 ,本题就是这两道题目的结合,建议自己独立做一做,本题涉及的知识,之前都讲过,没有新内容。

题目链接/文章讲解:代码随想录

视频讲解:回溯算法解决子集问题,如何去重?| LeetCode:90.子集II_哔哩哔哩_bilibili

题解思路:

跟着卡哥代码随想录刷,只要前几道题都理解了,这题和40.组合总和II思路类似,要进行数层去重,在40.组合总和II中有详细说明,这里自己手写ac出来了还是有点小成就感的!!!本题来说不算难,理解至上,可以多看卡哥视频讲解思路也很清晰!!!

class Solution {
    LinkedList<Integer> path = new LinkedList<>();
    List<List<Integer>> result = 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 result;
    }

    public void backtracking(int[] nums, int startIndex){
        result.add(new LinkedList<>(path));
        if(startIndex == nums.length ) {
            return;
        }
        for(int i = startIndex; i < nums.length; i++){
            if( i >= 1 && nums[i - 1] == nums[i] && used[ i - 1] == false){ //进行数层去重
                continue;
            }
            path.add(nums[i]);
            used[i] = true;
            backtracking(nums, i + 1);
            path.removeLast();
            used[i] = false;
        }
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值