【5.15 代随_27day】 组合总和、组合总和 II、分割回文串


组合总和

力扣连接:39. 组合总和(中等)

1.回溯的方法

本题是 集合里元素可以用无数次,那么和组合问题的差别 其实仅在于 startIndex上的控制

图解步骤

在这里插入图片描述

关键点

  • 本题元素为可重复选取的。

递归代码

class Solution {
    List<List<Integer>> result = new ArrayList<>();
    LinkedList<Integer> tmp = new LinkedList<>();
    public List<List<Integer>> combinationSum(int[] candidates, int target) {
        back(candidates, target, 0);
        return result;
    }

    public void back(int[] nums, int target, int startIndex){
        if(target==0){
            result.add(new ArrayList<>(tmp));
            return;
        }

        for(int i = startIndex; i<nums.length && target>0; i++){
            tmp.add(nums[i]);
            target -= nums[i];
            back(nums, target, i);
            target += nums[i];
            tmp.removeLast();
        }
    }
}


组合总和 II

力扣连接:40. 组合总和 II(中等)

1.回溯的方法

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

图解步骤

在这里插入图片描述

关键点

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

递归代码

class Solution {
    List<List<Integer>> result = new ArrayList<>();
    LinkedList<Integer> tmp = new LinkedList<>();
    public List<List<Integer>> combinationSum2(int[] candidates, int target) {
        Arrays.sort(candidates);
        back(candidates, target, 0, new int[candidates.length]);
        return result;
    }

    public void back(int[] nums, int target, int startIndex, boolean[] used){
        if(target==0){
            result.add(new ArrayList<>(tmp));
            return;
        }

        for(int i = startIndex; i<nums.length && target>0; i++){
            // used[i - 1] == 1,说明同一树枝candidates[i - 1]使用过
            // used[i - 1] == 0,说明同一树层candidates[i - 1]使用过
            // 要对同一树层使用过的元素进行跳过
            if(i>0 && nums[i]==nums[i-1] && used[i-1]==0){
                continue;
            }

            tmp.add(nums[i]);
            target -= nums[i];
            used[i] = 1;
            back(nums, target, i+1, used);
            used[i] = 0;
            target += nums[i];
            tmp.removeLast();
        }
    }
}


分割回文串

力扣连接:131. 分割回文串(中等)

切割问题的回溯搜索的过程和组合问题的回溯搜索的过程是差不多的。

图解步骤

在这里插入图片描述

关键点

来看看在递归循环中如何截取子串呢?

  • 在for (int i = startIndex; i < s.size(); i++)循环中,我们 定义了起始位置startIndex,那么 [startIndex, i] 就是要截取的子串。

代码

class Solution {
    List<List<String>> result = new ArrayList<>();
    LinkedList<String> tmp = new LinkedList<>();
    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<>(tmp));
            return;
        }

        for(int i = startIndex; i<s.length(); i++){
            if(isPalindrome(s, startIndex, i)){
                tmp.add(s.substring(startIndex, i+1));
            }else{
                continue;
            }

            backtracking(s, i+1);
            tmp.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;
    }

    // public boolean isPalindrome(String s, int startIndex, int endIndex){
    //     String sub = s.substring(startIndex, endIndex+1);
    //     int[] next = new int[sub.length()];
    //     getNext(next, sub);
    //     return next[sub.length()-1]==sub.length()-1;
    // }


    // public void getNext(int[] next, String s){
    //     next[0] = 0;
    //     int j = 0;

    //     for(int i = 1; i<s.length(); i++){
    //         //不相同的情况
    //         while(j>0 && s.charAt(i)!=s.charAt(j)){
    //             j = next[j-1];
    //         }
    //         //相同的情况
    //         if(s.charAt(i)==s.charAt(j)){
    //             j++;
    //         }
    //         //赋值
    //         next[i] = j;
    //     }
    // }
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值