先看一眼题:
我的思路:比如[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]加入结果队列,递归结束
···遍历23=6的时候,递归的找到一个3
······从下标0开始(值为1)遍历,(过程省略),将[2,2,2,1,1,1]加入结果队列,递归结束
···遍历24=6的时候,递归的找到一个1
······从下标0开始(值为1)遍历,(过程省略),将[2,2,2,2,1]加入结果队列,递归结束
···由于25>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;
}
实在是不想改了,要改动感觉工程还蛮大的,关键是写递归的这个思路没理清,所以看答案了。
看了答案,我吐了。答案的思路就是我这个思路,而且这种思路有一个名字,叫做回溯。回溯确实是用递归实现的,但是传入的参数和返回值一定要好好思考怎么写啊……
答案的代码就不放了,这个题马克一下,回来再看。学一下怎么用递归实现回溯。