[Likou Brush Questions] Day 23 - Backtracking Topic


Previous article: [Likou Brushing Questions] Day22 - Backtracking Topic_Tatakai!!!'s Blog-CSDN Blog

2. Segmentation problem

7. Split palindrome

Topic Link: 131. Splitting Palindrome Strings - LeetCode

The titles of enumeration schemes can be realized by backtracking method, enumerating all substrings of the string, and judging whether the substring is a palindrome string!

Code

class Solution {
    
    
    List<List<String>> res = new ArrayList<>();
    List<String> path = new ArrayList<>();
    int n;
    public List<List<String>> partition(String s) {
    
    
        n = s.length();
        dfs(s, 0);
        return res;
    }
    public void dfs(String s, int u){
    
    
        if(u == n){
    
    
            res.add(new ArrayList(path));
            return ;
        }
        // 从u开始枚举
        for(int i = u; i < n; i ++){
    
    
            if(is_huiwen(s.substring(u, i + 1))){
    
    
                path.add(s.substring(u, i + 1));
                dfs(s, i + 1);
                path.remove(path.size() - 1);
            }
        }
    }
    /**
        判断子串是否为回文串
     */
    public boolean is_huiwen(String s){
    
    
        char[] cs = s.toCharArray();
        int l = 0, r = cs.length - 1;
        while(l < r){
    
    
            if(cs[l] != cs[r]){
    
    
                return false;
            }else {
    
    
                l ++;
                r --;
            }
        }
        return true;
    }
}

8. Restoring the IP address

Topic Link: 93. Restoring IP Address - LeetCode

Idea: The IP address is composed of 4 segments, and the range of each segment is 3. 0~255Each segment has three chances. To choose 1/2/3one, we can judge whether it can constitute an IP address by enumerating whether the numbers of each segment meet the requirements of IP. Or is it reasonable.

It is worth noting that there cannot be a leading 0 before the number. When enumerating, the first character of this paragraph is 0, so this paragraph can only be 0!

Code

class Solution {
    
    
    List<String> res = new ArrayList<>();
    StringBuilder path = new StringBuilder();// 可能的一个ip
    public List<String> restoreIpAddresses(String s) {
    
    
        dfs(s, 0);// 0表示从第一段开始枚举
        return res;
    }
    public void dfs(String s, int u){
    
    
        if(u == 4 && s.length() == 0){
    
    
            res.add(path.toString());
            return ;
        }
        // 剪枝
        if(u > 4){
    
    
            return ;
        }

        // 枚举每一种可能
        for(int i = 0; i < s.length() && i < 3; i ++){
    
    // 每一段最多为3个数
            // 如果当前字符串的第一个字符为0,由于数字前置非0,那么本次ip地址的这一段只能为0,直接break本段
            if(i != 0 && s.charAt(0) == '0'){
    
    // 不是第一个字符 且为0
                break;
            }
            // 找到一个片段就进一步判断其合法性(每一段1/2/3个数)
            String tmp = s.substring(0, i + 1); // 
            if(Integer.valueOf(tmp) <= 255){
    
    
                if(path.length() != 0){
    
    
                    tmp = "." + tmp;
                }
                path.append(tmp);
                dfs(s.substring(i + 1), u + 1);// 枚举下一个
                path.delete(path.length() - tmp.length(), path.length());// 回溯
            }
            
        }
    }
}

3. Subset problem

9. Subset I

Topic link: 78. Subset - LeetCode

Idea 1: DFS enumeration index type (two options for each number: choose or not)

Code

class Solution {
    
    
    List<List<Integer>> res = new ArrayList<>();
    List<Integer> path = new ArrayList<>();
    int n;
    public List<List<Integer>> subsets(int[] nums) {
    
    
        n = nums.length;
        dfs(nums, 0);
        return res;
    }
    public void dfs(int[] nums, int u){
    
    
        if(u == n){
    
    
            res.add(new ArrayList(path));
            return ;
        }
        // 每一个数选或者不选

        // 选
        path.add(nums[u]);
        dfs(nums, u + 1);
        path.remove(path.size() - 1);

        // 不选
        dfs(nums, u + 1);
    }
}

Idea 2: Binary enumeration

Since there are only two options for each number, and the title clearly states that each number is different from each other, we use binary enumeration (0 means no choice, 1 means choice), and there are a total of 0 ~ 2^n - 1possibilities 2^n:

[1, 2, 3]:

000 []

001 [1]

010 [2]

011 [1, 2]

100 [3]

101 [1, 3]

Code

class Solution {
    
    
    public List<List<Integer>> subsets(int[] nums) {
    
    
        int n = nums.length;
        List<List<Integer>> res = new ArrayList<>();
        
        for(int i = 0; i < (1 << n); i ++){
    
    
            List<Integer> path = new ArrayList<>();
            for(int j = 0; j < n; j ++){
    
    
                if((i >> j & 1) == 1){
    
    
                    path.add(nums[j]);
                }
            }
            res.add(new ArrayList(path));
        }
        return res;
    }
}

10. Subset II

Topic link: 90. Subset II - LeetCode

The difference between this question and the previous question is that the array of this question may contain repeated elements, and the solution set cannot contain repeated subsets, so deduplication is required.

[1,2,2]
输出:[[],[1],[1,2],[1,2,2],[2],[2,2]]

How to deduplicate, that is, to ensure that each element can only be selected once, this question is very similar to Combination Sum III, they are all sorted and deduplicated, the difference is that this question seeks a subset, and Combination 2 seeks a combination that satisfies the conditions , such as a repeated segment 2 2 2 2 2 :

2 is a subset

2 2 is also a subset

2 2 2 is also a subset

Therefore, if we want to deduplicate, we cannot simply use "whether a certain subscript is selected" to make a decision, but to find a continuous segment of a certain value, and make a decision based on the selection class of the 次数value

Take the above continuum, and then decide to choose 0 times, choose 1 time, choose 2 times... so as to ensure that there will be no duplication

Code

class Solution {
    
    
    List<List<Integer>> res = new ArrayList<>();
    List<Integer> path = new ArrayList<>();
    int n;
    public List<List<Integer>> subsetsWithDup(int[] nums) {
    
    
        n = nums.length;
        Arrays.sort(nums);
        dfs(nums, 0);
        return res;
    }
    public void dfs(int[] nums, int u){
    
    
        if(u == n){
    
    
            res.add(new ArrayList(path));
            return ;
        }

        // 找出重复段
        int t = nums[u];
        int last = u;
        while(last < n && nums[last] == nums[u]) last ++;

        // 选:
        // 决策选择不同个数的 t 的情况:选择 1 个、2 个、3 个 ... k 
        for(int i = u; i < last; i ++){
    
    
            path.add(nums[i]);
            dfs(nums, last);
        }
        // 回溯
        for(int i = u; i < last; i ++){
    
    
            path.remove(path.size() - 1);
        }

        //不选: 选择0个
        dfs(nums, last);

    }
}

Guess you like

Origin blog.csdn.net/qq_54773252/article/details/127285946