回溯算法part2

回溯算法part2

39. 组合总和 - 力扣(LeetCode)

本题中,回溯函数参数会使用startIndex,那么,这个参数应该何时有何时无呢?

如果是一个集合来求组合的话,就需要startIndex,例如:77.组合 (opens new window)216.组合总和III (opens new window)

如果是多个集合取组合,各个集合之间相互不影响,那么就不用startIndex,例如:17.电话号码的字母组合

startIndex起到作用就是去重

代码如下:

class Solution {

    List<List<Integer>> res = new ArrayList<>();

    List<Integer> path = new ArrayList<>();

    public List<List<Integer>> combinationSum(int[] candidates, int target) {
        backtracking(candidates, target, 0, 0);
        return res;
    }

    public void backtracking(int[] candidates, int target, int sum, int startIndex){
        if(sum > target){
            return;
        }
        if(sum == target){
            res.add(new ArrayList<>(path));
            return ;
        }

        for(int i = startIndex; i < Math.min(150, candidates.length); i++){
            path.add(candidates[i]);
            sum += candidates[i];
            backtracking(candidates, target, sum, i);
            path.removeLast();
            sum -= candidates[i];
        }
    }
}

40. 组合总和 II - 力扣(LeetCode)

都知道组合问题可以抽象为树形结构,那么“使用过”在这个树形结构上是有两个维度的,一个维度是同一树枝上使用过,一个维度是同一树层上使用过。没有理解这两个层面上的“使用过” 是造成大家没有彻底理解去重的根本原因。

本题为什么要去重?

因为,candidates数组中有相同的数字,但是输出答案数组中不能有相同的数字

所以本题需要去重,去同一树层的重

去重逻辑:

if(i > startIndex && candidates[i] == candidates[i - 1]){
    continue;
}

总体代码:

class Solution {

    List<List<Integer>> res = new ArrayList<>();

    List<Integer> path = new ArrayList<>();

    public List<List<Integer>> combinationSum2(int[] candidates, int target) {
        Arrays.sort(candidates);
        backtracking(candidates, target, 0, 0);
        return res;
    }

    public void backtracking(int[] candidates, int target, int sum, int startIndex){
        if(sum > target){
            return ;
        }
        if(sum == target){
            res.add(new ArrayList<>(path));
            return ;
        }

        for(int i = startIndex; i < candidates.length; i++){
            if(i > startIndex && candidates[i] == candidates[i - 1]){
                continue;
            }
            path.add(candidates[i]);
            sum += candidates[i];
            backtracking(candidates, target, sum, i + 1);
            path.removeLast();
            sum -= candidates[i];
        }
    }
}

131. 分割回文串 - 力扣(LeetCode)

本题类型为分割类型,可以看作类组合问题,如图所示(理解此图就理解了为什么分割类问题可以看作类组合问题)

所以本题就可以用回溯算法的模板来做了,因为是一个集合中递归(一个String s),所以要有startIndex参数控制

本题另一个难点是回文串的选取,范围就是s.substring(startIndex, i) 注意substring函数为左闭右开。

String str = s.substring(startIndex, i + 1);

另一个难点是回文串的判断,直观想法是反转判断是否==,但是双指针明显更简单

public boolean isTrueStr(String str){
    for(int i = 0; i < str.length()/2; i++){
        if(str.charAt(i) == str.charAt(str.length() - i - 1)){
            continue;
        }else{
            return false;
        }
    }
    return true;
}

总体代码如下:

class Solution {

    List<List<String>> res = new ArrayList<>();

    List<String> path = new ArrayList<>(); 

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

    public void backtracking(String s, int startIndex) {
        //终止条件
        if(startIndex == s.length()){
            res.add(new ArrayList<>(path));
            return ;
        }

        for(int i = startIndex;  i < s.length(); i++){
            String str = s.substring(startIndex, i + 1);
            if(isTrueStr(str)){ // 是回文串
                path.add(str);
            }else{
                continue;
            }
            backtracking(s, i + 1);
            path.removeLast();

        }
    }

    public boolean isTrueStr(String str){
        for(int i = 0; i < str.length()/2; i++){
            if(str.charAt(i) == str.charAt(str.length() - i - 1)){
                continue;
            }else{
                return false;
            }
        }
        return true;
    }
}
posted @ 2025-06-16 20:32  泡芙猪  阅读(13)  评论(0)    收藏  举报