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

LeetCode 39. 组合总和

题目链接:https://leetcode.cn/problems/combination-sum/description/
文章链接:https://programmercarl.com/0039.%E7%BB%84%E5%90%88%E6%80%BB%E5%92%8C.html

思路

此题要求:candidates 中的数字可以无限制重复被选取。
在这里插入图片描述
注意图中叶子节点的返回条件,因为本题没有组合数量要求,仅仅是总和的限制,所以递归没有层数的限制,只要选取的元素总和超过target,就返回!
本题还需要startIndex来控制for循环的起始位置,对于组合问题,什么时候需要startIndex呢?
如果是一个集合来求组合的话,就需要startIndex。
如果是多个集合取组合,各个集合之间相互不影响,那么就不用startIndex

  private List<List<Integer>> res;
    private LinkedList<Integer> path;
    public List<List<Integer>> combinationSum(int[] candidates, int target) {
        res = new ArrayList<>();
        path = new LinkedList<>();
        backtracking(candidates, target, 0, 0);
        return res;
    }
    void backtracking(int[] candidates, int target, int startIndex, int sum) {
        if (sum == target) {
            res.add(new LinkedList<>(path));
            return;
        }
        if (sum > target) {
            return;
        }
        for (int i = startIndex; i < candidates.length; i++) {
            path.add(candidates[i]);
            // 关键点:不用i+1了,表示可以重复读取当前的数
            backtracking(candidates, target, i, sum + candidates[i]);
            path.removeLast();
        }
    }

LeetCode 40.组合总和II

题目链接:https://leetcode.cn/problems/combination-sum-ii/description/
文章链接:https://programmercarl.com/0040.%E7%BB%84%E5%90%88%E6%80%BB%E5%92%8CII.html

思路

解集不能包含重复的组合, 本题重点在于去重操作
在这里插入图片描述
此题还需要加一个int型数组used,用来记录同一树枝上的元素是否使用过,used[i]=1说明这个元素被使用过,used[i]=0说明没有被使用过。
前提是数组先排好序
如果candidates[i] == candidates[i - 1] 并且 used[i - 1] == false,就说明:前一个树枝,使用了candidates[i - 1],也就是说同一树层使用过candidates[i - 1]。
为什么 used[i - 1] == false 就是同一树层呢,因为同一树层,used[i - 1] == false 才能表示,当前取的 candidates[i] 是从 candidates[i - 1] 回溯而来的。
在这里插入图片描述

 private List<List<Integer>> result = new ArrayList<>();
    private LinkedList<Integer> path = new LinkedList<>();
    public List<List<Integer>> combinationSum2(int[] candidates, int target) {
        Arrays.sort(candidates);
        int[] used = new int[candidates.length];
        backtracking(candidates,target,0,0,used);
        return result;
    }
    void backtracking(int[] candidates, int target, int sum, int startIndex, int[] used) {
        if (sum == target) {
            result.add(new LinkedList<>(path));
        }
        if (sum > target)
            return;
        for (int i = startIndex; i < candidates.length; i++) {
            if (i > 0 && candidates[i] == candidates[i - 1] && used[i - 1] == 0)
                continue;
            path.add(candidates[i]);
            used[i] = 1;
            backtracking(candidates, target, sum + candidates[i], i + 1,used);
            used[i] = 0;
            path.removeLast();
        }
    }

LeetCode 131.分割回文串

题目链接:https://leetcode.cn/problems/palindrome-partitioning/description/
文章链接:https://programmercarl.com/0131.%E5%88%86%E5%89%B2%E5%9B%9E%E6%96%87%E4%B8%B2.html#%E7%AE%97%E6%B3%95%E5%85%AC%E5%BC%80%E8%AF%BE

思路

所以切割问题,也可以抽象为一棵树形结构,如图:
在这里插入图片描述
从树形结构的图中可以看出:切割线切到了字符串最后面,说明找到了一种切割方法,此时就是本层递归的终止条件。

  private List<List<String>> result = new ArrayList<>();
    private List<String> path = 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 ArrayList<>(path));
            return;
        }
        // 单层搜索
        for (int i = startIndex; i < s.length(); i++) {
            // 子串范围[startIndex,i]
            // 判断是否是回文,是回文加入path
            if (palindrome(s.substring(startIndex, i + 1))) {
                path.add(s.substring(startIndex, i + 1));
            } else {
                continue;
            }
            backTracking(s, i + 1);
            // 回溯
            path.remove(path.size() - 1);
        }
    }
    private boolean palindrome(String s) {
        for (int i = 0, j = s.length() - 1; i < j; i++, j--) {
            if (s.charAt(i) != s.charAt(j)){
                return false;
            }
        }
        return true;
    }
代码随想录算法训练营是一个优质的学习和讨论平台,提供了丰富的算法训练内容和讨论交流机会。在训练营中,学员们可以通过观看视频讲解来学习算法知识,并根据讲解内容进行刷题练习。此外,训练营还提供了刷题建议,例如先看视频、了解自己所使用的编程语言、使用日志等方法来提高刷题效果和语言掌握程度。 训练营中的讨论内容非常丰富,涵盖了各种算法知识点和解题方法。例如,在第14训练营中,讲解了二叉树的理论基础、递归遍历、迭代遍历和统一遍历的内容。此外,在讨论中还分享了相关的博客文章和配图,帮助学员更好地理解和掌握二叉树的遍历方法。 训练营还提供了每日的讨论知识点,例如在第15的讨论中,介绍了层序遍历的方法和使用队列来模拟一层一层遍历的效果。在第16的讨论中,重点讨论了如何进行调试(debug)的方法,认为掌握调试技巧可以帮助学员更好地解决问题和写出正确的算法代码。 总之,代码随想录算法训练营是一个提供优质学习和讨论环境的平台,可以帮助学员系统地学习算法知识,并提供了丰富的讨论内容和刷题建议来提高算法编程能力。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* *3* [代码随想录算法训练营每日精华](https://blog.csdn.net/weixin_38556197/article/details/128462133)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 100%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值