代码随想录第二十七天|

Leetcode 39. 组合总和

题目链接: 组合总和
自己的思路:一开始自己想到了,但是在把path加入到res中的时候没有new一个对象;导致一直出错!!!!

正确思路:和组合总和III类似,只不过区别在于,可以使用重复的元素,而且每个数组的长度没有限制,这样每次进行递归的时候,传入的startindex是i就可以了,因为可以重复,我们只需要满足当前的和等于target时直接返回就可以了;还有比较重要的剪枝操作,先把数组排序,然后当cursum大于target的时候,直接后面的都可以不用递归了,因为是递增的数组;回溯三部曲:1、传入参数:数组、目标和、当前和以及起始索引;2、终止条件:当满足当前和等于目标和的时候,加入数组,然后返回;3、单层逻辑:考虑剪枝,当当前和大于target的时候,后面都可以不要了,把当前值加入到path中,然后cursum加上当前值,然后递归,然后path弹出最后一个元素,cursum再减去当前值!!!!

代码:

class Solution {
    List<List<Integer>> res = new ArrayList<>();
    LinkedList<Integer> path= new LinkedList<>();
    
    public List<List<Integer>> combinationSum(int[] candidates, int target) {
        //排序用于剪枝
        Arrays.sort(candidates);
        backtracking(candidates,target,0,0);
        return res;
    }

    public void backtracking(int[] candidates,int target,int cursum,int startindex){
        if(cursum==target){
            //记得一定要新new一个对象,因为java是值传递
            res.add(new ArrayList(path));
            return;
        }
        for (int i=startindex;i<candidates.length;i++){
            //如果当前的和大于target,那么后面所有的都会大于target,所以直接剪枝(因为数组是递增的)
            if (cursum+candidates[i]>target) break;
            path.add(candidates[i]);
            cursum+=candidates[i];
            backtracking(candidates,target,cursum,i);
            path.removeLast();
            cursum-=candidates[i];
        }
    }
}

复杂度分析
时间复杂度: O ( n ) \mathcal{O}(n) O(n)
空间复杂度: O ( 1 ) \mathcal{O}(1) O(1)

Leetcode 40. 组合总和 II

题目链接: 组合总和 II
自己的思路:没想到如何去去重!!!
正确思路:去重分为两种,一个是数层去重,一个是树枝去重;这个题分析出来应该是数层去重,即每个数组中可以使用相同数值的数,但是不可以出现重复的数组;数层去重就是要定义一个used数组,用来标记是否已经使用过一个数,如果说当前元素的前一个元素我们没有使用过,说明是数层,否则是树枝,所以我们去重的逻辑是,当前的数如果等于前一个数而且前一个数如果没有使用过,则直接continue,去重;回溯三部曲:1、传入参数:数组、目标和、当前和、起始索引以及used数组;2、终止条件:当满足当前和等于目标和的时候,加入数组,然后返回;3、单层逻辑:考虑剪枝,当当前和大于target的时候,后面都可以不要了;考虑去重,如果是树层重复,则去重;把当前值加入到path中,然后cursum加上当前值,然后递归,然后path弹出最后一个元素,cursum再减去当前值!!!!

代码:

class Solution {
    Set<List<Integer>> res = new HashSet<>();
    LinkedList<Integer> path = new LinkedList<>();
    public List<List<Integer>> combinationSum2(int[] candidates, int target) {
        Arrays.sort(candidates);
        //用来标记是否已经使用过某个数字
        boolean[] used = new boolean[candidates.length];
        Arrays.fill(used,false);
        backtracking(candidates,target,0,0,used);
        return new ArrayList<>(res);
    }

    public void backtracking(int[] candidates, int target,int cursum,int startindex,boolean[] used){
        if (cursum==target){
            res.add(new ArrayList(path));
            return;
        }
        for (int i=startindex;i<candidates.length;i++){
            //剪枝
            if (cursum+candidates[i]>target) break;
            //去重
            if (i>0&&candidates[i]==candidates[i-1]&&!used[i-1]) continue;
            used[i]=true;
            path.add(candidates[i]);
            cursum+=candidates[i];
            backtracking(candidates,target,cursum,i+1,used);
            used[i]=false;
            path.removeLast();
            cursum-=candidates[i];
        }
    }
}

复杂度分析
时间复杂度: O ( n ) \mathcal{O}(n) O(n)
空间复杂度: O ( 1 ) \mathcal{O}(1) O(1)

Leetcode 131. 分割回文串

题目链接: 分割回文串
自己的思路:没想到,难点在于如何去切割回文串,没有想到按区间去切割!

正确思路:和组合一个思路;只不过在组合的基础上要切割子串并且判断是否是回文串,如果是回文串才会加入到数组中;回溯三部曲:1、传入参数:字符串以及其指向其字符位置的指针;2、终止条件:当指向其最后的位置的时候,将path加入,然后返回;3、单层逻辑:先对一段区间的字符串进行判断是否是回文串(区间是[startindex,i]),如果是则加入到path中,不是的话就会continue,指针向后指,然后进行递归回溯即可!!!

代码:

class Solution {
    List<List<String>> res = new ArrayList<>();
    LinkedList<String> path = new LinkedList<>();
    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++){
            //如果是回文则记录
            if (ishuiwen(s,startindex,i)){
                String str = s.substring(startindex,i+1);
                path.add(str);
            }else continue;

            backtracking(s,i+1);
            path.removeLast();
        }
    }
    //判断是否是回文串
    public boolean ishuiwen(String s,int left,int right){
        while(left<=right){
            if (s.charAt(left)!=s.charAt(right)) return false;
            left++;
            right--;
        }
        return true;
    }
}

复杂度分析
时间复杂度: O ( n ) \mathcal{O}(n) O(n)
空间复杂度: O ( 1 ) \mathcal{O}(1) O(1)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值