Code Caprice Recording Algorithm Training Camp Day 28 | 93. Restoring IP Addresses, 78. Subsets, 90. Subsets II

Table of contents

93. Restoring IP address

78. Subset

90. Subset II


93. Restoring IP address

This issue was originally very difficult, but after everyone finished dividing the palindrome string, this question will be much easier

Topic link/article explanation: code caprice

Video explanation: How does the backtracking algorithm split a string and determine whether it is a legal IP? | LeetCode: 93. Recover IP address_哔哩哔哩_bilibili

Solution ideas:

After watching Kage’s video, the idea of ​​this question is still clear. Some details in it must be paid attention to. For the specific implementation method and code, see the comments. ! !

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. Subset

The subset problem is to collect the results of each node in the tree structure. The overall code is actually similar to the backtracking template.

Topic link/article explanation: code caprice

Video explanation: the backtracking algorithm solves the subset problem, and the nodes on the tree are all target sets! | LeetCode: 78. Subset_哔哩哔哩_bilibili

Solution ideas:

It is a very routine question. I wrote it myself without looking at the solution. After writing so many questions, I still have muscle memory! ! ! The code can be written by drawing the tree structure first, and then the difference from the previous backtracking algorithm topic is that the result is collected when a leaf node is encountered before, but this question needs to collect the result every time it recurses.

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. Subset II

You have done 40. Combined sum II and 78. Subset before. This question is a combination of these two questions. It is recommended to do it independently. The knowledge involved in this question has been mentioned before, and there is no new content.

Topic link/article explanation: code caprice

Video explanation: Backtracking algorithm solves the subset problem, how to remove duplicates? | LeetCode: 90. Subset II_哔哩哔哩_bilibili

Solution ideas:

Follow Kage's code to record and brush, as long as you understand the first few questions, this question is similar to 40. Combination sum II. It needs to be deduplicated by several layers. It is explained in detail in 40. Combination sum II. Here I write ac by myself There is still a little sense of accomplishment when it comes out! ! ! This question is not difficult, understanding is paramount, you can watch more Ka Ge video explanations and the ideas are very clear! ! !

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;
        }
    }
}

Guess you like

Origin blog.csdn.net/tore007/article/details/130711275