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

 39. 组合总和 
class Solution {
    List<List<Integer>> ans = new ArrayList<>();
    List<Integer> list = new ArrayList<>();

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

    public void backTracking(int[] candidates, int target,int sum, int startIndex) {
        if (sum == target) {
            ans.add(new ArrayList<>(list));
            return;
        }
        for (int i = startIndex; i < candidates.length; i++) {
            if (sum + candidates[i] > target) continue;
            list.add(candidates[i]);
            int newSum = sum + candidates[i];
            backTracking(candidates, target, newSum, i);
            list.removeLast();
        }
    }
}

39. 组合总和

40.组合总和II 

本题开始涉及到一个问题了:去重。

我们要去重的是同一树层上的“使用过”,同一树枝上的都是一个组合里的元素,不用去重。

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

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

class Solution {
    List<List<Integer>> ans = new ArrayList<>();
    List<Integer> list = new ArrayList<>();
    public List<List<Integer>> combinationSum2(int[] candidates, int target) {
        Arrays.sort(candidates);
        backTracking(candidates, target, 0, 0);
        return ans;
    }

    public void backTracking(int[] candidates, int target, int sum, int startIndex) {
        if (sum == target) {
            ans.add(new ArrayList<>(list));
            return;
        }
        for (int i = startIndex; i < candidates.length; i++) {
            if (sum + candidates[i] > target) continue;
            if (i > startIndex && candidates[i] == candidates[i - 1]) continue;
            list.add(candidates[i]);
            backTracking(candidates, target, sum + candidates[i], i + 1);
            list.removeLast();
        }
    }
}

 131.分割回文串  

代码随想录

视频讲解:带你学透回溯算法-分割回文串(对应力扣题目:131.分割回文串)| 回溯法精讲!_哔哩哔哩_bilibili

class Solution {
    List<List<String>> ans = new ArrayList<>();
    List<String> list = new ArrayList<>();

    public List<List<String>> partition(String s) {
        backTracking(s, 0);
        return ans;
    }

    public void backTracking(String s, int startIndex) {
        if (startIndex == s.length()) {
            ans.add(new ArrayList<>(list));
            return;
        }
        for (int i = startIndex; i < s.length(); i++) {
            if (isPalindrome(s, startIndex, i)) {
                String str = s.substring(startIndex, i + 1); //substring 左闭右开截取
                list.add(str);
            } else {
                continue;
            }
            backTracking(s, i + 1);
            list.removeLast();
            
        }
    }

     private 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;
     }
}

模拟这段代码的执行流程,以字符串 "aab" 为例:

  1. 开始调用 partition("aab") 方法

    • 这个方法调用 backTracking("aab", 0)
  2. 进入 backTracking 方法,此时 startIndex = 0

    • 循环开始,i 从 0 到 2(字符串 "aab" 的长度减 1)。
  3. 第一轮循环i = 0

    • 调用 isPalindrome("aab", 0, 0),检查 "a" 是否是回文。是的,因此继续。
    • s.substring(0, 0 + 1) → 截取 "a",并添加到 list 中,现在 list = ["a"]
    • 递归调用 backTracking("aab", 1)
  4. 进入 backTracking 的下一层递归,此时 startIndex = 1

    • 循环开始,i 从 1 到 2。
    • 第一轮循环i = 1
      • 调用 isPalindrome("aab", 1, 1),检查 "a" 是否是回文。是的,因此继续。
      • s.substring(1, 1 + 1) → 截取 "a",并添加到 list 中,现在 list = ["a", "a"]
      • 递归调用 backTracking("aab", 2)
  5. 进入更深层的递归,此时 startIndex = 2

    • 循环开始,i 从 2 到 2。
    • 第一轮循环i = 2
      • 调用 isPalindrome("aab", 2, 2),检查 "b" 是否是回文。是的,因此继续。
      • s.substring(2, 2 + 1) → 截取 "b",并添加到 list 中,现在 list = ["a", "a", "b"]
      • 递归调用 backTracking("aab", 3)
  6. 递归基准情况满足startIndex == s.length()),将 ["a", "a", "b"] 添加到 ans 中。

    • 回溯:移除 list 中最后一个元素,list 变回 ["a", "a"]
  7. 回溯到 startIndex = 1 的层次

    • 回溯后的循环继续,i 变为 2。
    • 检查 "aab" 的子串 "ab"s.substring(1, 2 + 1))是否是回文。不是,因此跳过。
    • 循环结束,执行 list.removeLast(),移除 "a"list 变回 ["a"]
  8. 回到最初的 backTracking 调用,此时 startIndex = 0

    • 循环继续,i 变为 1。
    • 检查 "aab" 的子串 "aa"s.substring(0, 1 + 1))是否是回文。是的,因此继续。
    • 添加 "aa"list 中,现在 list = ["a", "aa"]
    • 递归调用 backTracking("aab", 2)
  9. 再次进入递归,此时 startIndex = 2

    • 循环开始,i 从 2 到 2。
    • 检查 "b" 是否是回文。是的,因此继续。
    • 添加 "b"list 中,现在 list = ["a", "aa", "b"]
    • 递归调用 backTracking("aab", 3)
  10. 基准情况满足,将 ["a", "aa", "b"] 添加到 ans 中。

    • 回溯:移除 list 中最后一个元素,list 变回 ["a", "aa"]
  11. 回溯到 startIndex = 0 的层次

    • 回溯后的循环结束,执行 list.removeLast(),移除 "aa"list 变回 ["a"]
  12. 所有循环结束,所有可能的分割方式已经被添加到 ans 中。

最终,ans 包含了所有可能的分割方式:[["a", "a", "b"], ["aa", "b"]]。通过这种方式,代码逐步探索了不同的子串分割方式,每次都检查是否为回文,并适时地进行回溯以探索不同的路径。

  • 9
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值