Code Caprice Algorithm Training Camp Day 27 | 39. Combined Sum, 40. Combined Sum II, 131. Split Palindrome String

Table of contents

39. Combined sum

40. Combined Sum II

131. Split palindrome


39. Combined sum

This problem is that the elements in the collection can be used countless times, so the difference from the combination problem is actually only the control on startIndex

Topic link/article explanation: code caprice

Video explanation: Take you to learn the backtracking algorithm-combined sum (corresponding to "leetcode" buckle topic: 39. Combined sum) | Intensive lecture on backtracking method! _哔哩哔哩_bilibili

Solution ideas:

This is the code idea of ​​the basic backtracking algorithm to find the combination problem. There is no problem. To be able to ac means to record the first time without reading the question to explain the question. The idea is the essence of the violent algorithm. The optimization routine of the pruning condition is actually similar. Here is There is an additional operation of sorting the array in ascending order first, which is more conducive to judging the pruning conditions! ! !

class Solution {
    LinkedList<Integer> path = new LinkedList<>();
    List<List<Integer>> result = new ArrayList<>();
    int sum = 0;
    public List<List<Integer>> combinationSum(int[] candidates, int target) {
        Arrays.sort(candidates); //使用Arrays工具类对给定的数组先按升序排列,好让回溯方法里面的剪枝条件作快速判断
        backtracking(candidates,target,0);
        return result;
    }

    public void backtracking(int[] candidates, int target, int satart){
        if(sum > target) return;  //先对数组进行升序排序,可以更加对其作判断,不加也没事就是说
        if(sum == target){
            result.add(new LinkedList<Integer>(path));
            return;
        }
        for(int i = satart; i < candidates.length; i++){
            path.add(candidates[i]);
            sum += candidates[i];
            backtracking(candidates,target,i); //这里是i因为避免取到重复的组合
            path.removeLast();
            sum -= candidates[i];
        }
    }
}

40. Combined Sum II

This question begins to involve a problem: deduplication.

Note that the set given to us in the question has repeated elements, so the obtained combination may be repeated, but the question requires that there should be no repeated combination.

Topic link/article explanation: code caprice

Solution ideas:

This question mainly lies in the understanding of deduplication conditional operation, which is very important! ! ! Then the overall idea is similar to the combination problem. The specific deduplication operation understanding can be divided into two types: tree layer deduplication and branch deduplication. Taking this question combined with code comments as an example, the description is as follows: The first tree layer deduplication
: used [ i - 1] == false --> Indicates that the first round of recursion has ended at this time, and the judgment condition of the entire if statement at this time means: when the second round of recursion begins, the beginning element and the beginning of the first round of recursion When the elements are the same, skip this round of recursion directly, because the previous round has already included all kinds of combinations starting with 1; the
second branch deduplication : used[i - 1] == true --> shows that it is still In the first round, the judgment condition of the entire if statement at this time means: when searching for all combinations in the first round, if the same element as the previous element is encountered, directly skip the search for the same combination of adjacent elements, This means that the combination of [1 1 6] will not appear, which is obviously wrong. The
last thing I want to share is that you can watch more of the ideas explained in Ka Ge’s video, and then understand these two situations by yourself! ! !

class Solution {
    LinkedList<Integer> path = new LinkedList<>();
    List<List<Integer>> result = new ArrayList<>();
    int sum = 0;
    boolean[] used;

    public List<List<Integer>> combinationSum2(int[] candidates, int target) {
        Arrays.sort(candidates); //先对数组进行排序
        used = new boolean[candidates.length]; //定义一个和给定数组相同大小、具有标记功能的数组
        Arrays.fill(used, false); //使用used数组标记之前是否使用过元素,0表示未使用过,1表示使用过
        backtracking(candidates, target, 0);
        return result;
    }

    public void backtracking(int[] candidates, int target, int start){
        if(sum > target) return;
        if(sum == target){
            result.add(new LinkedList<Integer>(path));
            return;
        }
        for(int i = start; i < candidates.length; i++){
            if(i > 0 && candidates[i - 1] == candidates[i] && used[i - 1] == false) continue; //used[i - 1] == false:树层去重操作;used[i - 1] == true:树枝去重操作
            //这里可以这么去理解这种判断条件:(以第一轮和第二轮递归说明,给定的排序后的数组为[1 1 2 5 6 7],target = 8)
            //used[i - 1] == false --> 说明此时第一轮递归已经结束了,此时整个if语句的判断条件意思是:当第二轮开始递归的开头元素和第一轮开始的递归的开头元素相同时,直接跳过此轮递归,因为之前那一轮已经包括了所有种以1开头的组合;
            //used[i - 1] == true --> 说明此时还在第一轮里面,此时整个if语句的判断条件意思是:当在第一轮搜索所有的组合过程中,如果遇到和前一个元素相同时,直接跳过相邻元素相同组合的搜索,这就意味着不会出现 [ 1 1 6]这种组合了,显然是错误的
            used[i] = true;
            path.add(candidates[i]);
            sum += candidates[i];
            backtracking(candidates, target, i + 1);
            used[i] = false; //递归之后一定要回溯,这是不能忘的!把之前使用过的元素重新都标记为0,开始下一次的递归搜索
            path.removeLast();
            sum -= candidates[i];
        }
    }
}

131. Split palindrome

This question is more difficult. Please watch the video first to understand the segmentation problem. There will be another segmentation problem tomorrow, so let's lay the foundation first.

Topic link/article explanation: code caprice

Solution ideas:

This question is still difficult. It is necessary to abstract the cutting action into a combined problem. Watch the ideas explained in the Kage video, and then write the execution code by hand after clarifying it! ! ! The ideas mentioned in Ka Ge are still very clear, just taste more! ! ! Please refer to the comments for the specific attention of the code, how to abstract the cutting action into a combination problem, the video of Ka Ge is very detailed, just move to the video of Ka Ge! ! !

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

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

    public void backtracking(String s, int startIndex){
        if(startIndex >= s.length()){ 
            result.add(new LinkedList<String>(path));
            return;
        }
        for(int i = startIndex; i < s.length(); i++){
            if(isPalindrome(s, startIndex, i)){ //如果索引的范围内的子串是回文串,则直接切割子串及时添加到path路径里面,这里使用下标直接进行切割数组的操作,不用装到容器里面判断
                String temp = s.substring(startIndex, i + 1); //startIndex是固定不变的,而i会在每轮递归的时候都会进行i++操作,主要substring(start,end)是左闭右开的
                path.add(temp);
            }else{
                continue;
            }
             backtracking(s, i + 1); //下一轮递归的时候i = i+1, 保证不会重复切割
             path.removeLast();
        }
    }

    public boolean isPalindrome(String s, int startIndex, int end){
        for(int i = startIndex, j = end; i < j; i++, j--){
            if(s.charAt(i) != s.charAt(j)){
                return false;
            }
        }
        return true;
    }

}

Guess you like

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