代码随想录训练营第二十三天| 39. 组合总和 40.组合总和II 131.分割回文串

39. 组合总和

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

视频讲解:带你学透回溯算法-组合总和(对应「leetcode」力扣题目:39.组合总和)| 回溯法精讲!_哔哩哔哩_bilibili

//组合问题要考虑是不是在一个集合里操作
//最常见的就是递归回溯法
//再考虑考虑剪枝
class Solution{
    public List> combinationSum(int[] candidates, int target){
        List> ans = new ArrayList<>();
        Arrays.sort(candidates);//先进行排序
        backtracking(ans, new ArrayList<>(), candidates, target, 0, 0);
        return ans;
    }

    public void backtracking(List> ans, List path, int[] candidates, int target, int sum, int index){
        //找到了数字和为target的组合
        //剪枝一下 如果当前sum + candidate[i] > target 可以直接不进行递归 不必多余判断
        if(sum == target){
            ans.add(new ArrayList<>(path));
            return;
        }

        for(int i = index; i < candidates.length && candidates[i] + sum <= target; i++){
            path.add(candidates[i]);
            backtracking(ans, path, candidates, target, sum + candidates[i], i);
            path.remove(path.size() - 1);//回溯 移除路径path最后一个元素
        }
    }
}

感觉稍微自己能理解一下回溯了 能跟着循环走一遍思路 对每个位置应该有的参数有了想法

 40.组合总和II

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

视频讲解:回溯算法中的去重,树层去重树枝去重,你弄清楚了没?| LeetCode:40.组合总和II_哔哩哔哩_bilibili

 集合里有重复元素 但是不能选出的组合不能有重复的 此时就要对 树层进行剪枝 树枝不需要剪枝

Java代码:

class Solution {
    LinkedList path = new LinkedList<>();
    List> ans = new ArrayList<>();
    int sum = 0;
    public List> combinationSum2(int[] candidates, int target) {
        //先排序后递归剪枝回溯
        Arrays.sort(candidates);
        backtracking(candidates, target, 0);
        return ans;
    }

    private void backtracking(int[] candidates, int target, int startindex){
        if(sum == target){
            ans.add(new ArrayList<>(path));
            return;
        }
        for(int i = startindex; i < candidates.length && candidates[i] + sum <= target; i++){
            //接下来树层剪枝 跳过同一树层的剪枝
            if(i > startindex && candidates[i] == candidates[i - 1]){
                continue;
            }
            sum += candidates[i];
            path.add(candidates[i]);
            // i + 1 代表当前组内元素只选一次 不重复选择
            backtracking(candidates, target, i + 1);

            int temp = path.getLast();
            sum -= temp;//回溯
            path.removeLast();
        }
    }
}

 131.分割回文串

题目链接:131. 分割回文串 - 力扣(LeetCode)

讲解链接:代码随想录

这道题重点在于什么是分割 怎么转化为组合 怎么分割 怎么在递归循环里截取子串 子串里是否回文 需要多加练习

Java代码:

class Solution{
    List> ans = new ArrayList<>();
    List str = new ArrayList<>();
    public List> partition(String s){
        backtracking(s, 0, new StringBuilder());
        return ans;
    }
    private void backtracking(String s, int startindex, StringBuilder sb){
        //因为起始位置一个一个加 所以结束时startindex一定等于s.length,
        //因为进入backtracking时
        //一定末尾也是回文 所以str是满足条件的
        if(startindex == s.length()){   
            ans.add(new ArrayList<>(str));
            return;
        }
        //从后往前搜索 如果发现回文 进入backtracking 起始位置后移动一位 循环结束
        for(int i = startindex ; i < s.length(); i++){
            sb.append(s.charAt(i));
            if(check(sb)){
                str.add(sb.toString());
                backtracking(s, i + 1, new StringBuilder());
                str.remove(str.size() - 1);
            }
        }
    }
    private boolean check(StringBuilder sb){
        for(int i = 0; i < sb.length() / 2; i++){
            if(sb.charAt(i) != sb.charAt(sb.length() - i - 1)) return false;
        }
        return true;
    }
}

你可能感兴趣的:(算法)