力扣第39题 组合总和 中等难度 卡了一天没做出来

先看一眼题:
在这里插入图片描述

我的思路:比如[1,2,6],target=9
先找到大于等于9的数,没有则找到数组长度length
从length-1遍历到0,
比如这里:
从6开始遍历,遍历到最前面为止
···遍历6的时候,递归的寻找一个3,使得3+6等于9
······递归时,target变为3
······先找到大于等于3的数,然后其下标-1
······比如这里,从2开始遍历,遍历到最前面为止
······遍历2的时候,递归的找到一个1,使得1+2等于3
·········递归时,target变为1
·········先找到大于等于1的数,然后其下标-1
·········下标为-1,退出递归
······此时将[6,2,1]加入结果队列
······遍历1的时候,将[6,1,1,1]加入结果队列
······由于1前面没有数,递归结束
···遍历2的时候,递归找到一个7
······递归时,target变为7
······从下标0开始(值为1)遍历,(过程省略),将[2,1,1,1,1,1,1,1]加入结果队列,递归结束
···遍历22=4的时候,递归的找到一个5
······从下标0开始(值为1)遍历,(过程省略),将[2,2,1,1,1,1,1]加入结果队列,递归结束
···遍历2
3=6的时候,递归的找到一个3
······从下标0开始(值为1)遍历,(过程省略),将[2,2,2,1,1,1]加入结果队列,递归结束
···遍历24=6的时候,递归的找到一个1
······从下标0开始(值为1)遍历,(过程省略),将[2,2,2,2,1]加入结果队列,递归结束
···由于2
5>9,故遍历结束,递归结束
···遍历1的时候,由于[1,1,1,1,1,1,1,1,1]满足条件,将其加入结果队列
···由于1前面没有数,无法递归遍历,因此递归结束
结束,返回结果队列


思路是没错的,但是代码写起来出问题了,大概知道哪里出问题了,返回值没设定好,错误代码如下:

public static List<List<Integer>> combinationSum(int[] candidates, int target) {
        Arrays.sort(candidates);
        List<List<Integer>> resList = new ArrayList<>();
        int index;
        //首先找到距离target最近的较大值或者target本身,从它-1开始对数组前面的元素进行遍历
        for (index = 0; index < candidates.length; index++) {
            if (candidates[index] == target) {
                List<Integer> list = new ArrayList<>();
                list.add(target);
                resList.add(list);
                break;
            } else if (candidates[index] > target) {
                break;
            }
        }
        for (int i = index - 1; i >= 0; i--) {
            //index对应的元素可能是由i对应的数的n倍+tar(新的target的简称)决定的
            for (int k = 1; k * candidates[i] <= target; k++) {
                List<Integer> list = new ArrayList<>();
                int old = k * candidates[i];
                //先放入k个candidates[i]
                for (int j = 0; j < k; j++) {
                    list.add(candidates[i]);
                }
                if (old == target) {
                    resList.add(list);
                } else {
                    //寻找target-old
                    int r = find(candidates, target - old, list, i, resList);
                    //如果r==target-old,说明list里面没有-1
                    if (r == target - old) {
                        resList.add(list);
                    }
                }
            }
        }
        return resList;
    }

    //从arr[0,right)里找一个新的target,使得新的target+当前数==target,返回值为新的target
    //找不到则返回-1
    public static int find(int[] arr, int target, List<Integer> list, int right, List<List<Integer>> resList) {
        //首先找到距离target最近的较大值或者target本身,从它-1开始对数组前面的元素进行遍历
        int index;
        boolean firstT = false;
        for (index = 0; index < right; index++) {
            if (arr[index] == target) {
                list.add(target);
                resList.add(list);
                firstT = true;
                //注意:此时虽然找到了满足的数,但是这个数也有可能是比它更小的多个数组成
                //这两种情况都要加入resList
                //但是也有可能不存在比它更小的多个数组成,避免错误的返回-1,所以引入firstT
                //因为list是指针,所以不能直接remove
                list = new ArrayList<>(list);
                list.remove((Integer) target);
                break;

            } else if (arr[index] > target) {
                break;
            }
        }
        for (int i = index - 1; i >= 0; i--) {
            //index对应的元素可能是由i对应的数的n倍+tar(新的target的简称)决定的
            for (int k = 1; k * arr[i] <= target; k++) {
                int old = k * arr[i];
                //先放入k个arr[i]
                for (int j = 0; j < k; j++) {
                    list.add(arr[i]);
                }
                if (old == target) {
                    resList.add(list);
                    return target;
                } else {
                    //寻找target-old
                    int r = find(arr, target - old, list, i, resList);
                    //如果r==target-old,说明list里面没有-1
                    if (r == target - old) {
                        resList.add(list);
                        return r;
                    } else if (r == -1) {
                        //移除list里放入的那个数
                        for (int j = 0; j < k; j++) {
                            list.remove((Integer) arr[i]);
                        }
                    }
                }
            }
        }
        if (firstT)
            return target;
        return -1;
    }

实在是不想改了,要改动感觉工程还蛮大的,关键是写递归的这个思路没理清,所以看答案了。
看了答案,我吐了。答案的思路就是我这个思路,而且这种思路有一个名字,叫做回溯。回溯确实是用递归实现的,但是传入的参数和返回值一定要好好思考怎么写啊……
答案的代码就不放了,这个题马克一下,回来再看。学一下怎么用递归实现回溯

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值