给定一个无重复元素的数组 candidates
和一个目标数 target
,找出 candidates
中所有可以使数字和为 target
的组合。
candidates
中的数字可以无限制重复被选取。
说明:
- 所有数字(包括
target
)都是正整数。 - 解集不能包含重复的组合。
示例 1:
输入: candidates =[2,3,6,7],
target =7
, 所求解集为: [ [7], [2,2,3] ]
示例 2:
输入: candidates = [2,3,5],
target = 8,
所求解集为:
[
[2,2,2,2],
[2,3,3],
[3,5]
]
啊,此题真是,一言难尽啊,先上报错代码(因为一直找不到错误,还以为逻辑错了,就把C/C++的正确代码重写了一遍,没想到还是一直报错,最后灵机一动,想到值传递这件事,才AC代码):
package LeetCode;
import java.util.*;
public class Lee_39_SumOfZuHe {
public static void main(String[] args){
int[] candidates = new int[]{2,3,6,7};
int target = 7;
new Lee_39_SumOfZuHe().combinationSum(candidates,target);
}
public List<List<Integer>> combinationSum(int[] candidates, int target) {
List<List<Integer>> list = new ArrayList<List<Integer>>();
List<Integer> mylist = new ArrayList<Integer>();;
Arrays.sort(candidates);
//System.out.println(Arrays.toString(candidates));
ReccombinationSum(candidates,target,0,mylist,list);
//System.out.print(list);
return list;
}
public void ReccombinationSum(int[] Newcandidates,int sum,int start,List<Integer> mylist,List<List<Integer>> list){
if(sum<0)
return;
else if(sum==0){
list.add(mylist);
return;
}
else{
for(int i=start;i<Newcandidates.length;i++){
int current = Newcandidates[i];
mylist.add((Integer)current);
ReccombinationSum(Newcandidates,sum-current,i,mylist,list); //主要是此行代码
mylist.remove((Integer)current);
}
}
}
}
结果跑出了空结果:
加了一行检测代码,发现能跑出正确结果,说明只是list没能真正添加元素:
那么问题出在哪呢?难受啊兄die~~~
后面理解了值传递,改了代码:
ReccombinationSum(Newcandidates,sum-current,i,mylist,list);
ReccombinationSum(Newcandidates,sum-current,i,new ArrayList<Integer>(mylist),list);
可以看见,主要是在递归过程中重新创建了对象,其实理解了java的值传递模式就能理解了,当mylist作为形参进行传递时,传递的是mylist的地址值,当然可以通过对mylist的地址值对对象进行操作,然而如果不重新new一个mylist出来,在进行list.add(mylist)的时候,只会把这一个对象进行add,然而再往后递归的时候,由于mylist是一个对象,mylist先add后remove自然会将mylist清空,而list真正add的其实是mylist的地址,add了两次其实是add了mylist这一个对象两次,然后mylist又被清空,所以结果只能是[ [ ] , [ ] ],更改代码后,结果AC~~~
话说回来,博主之前也做过类似的递归题,不过由于用的不是list这样通过地址值传递的递归,而是利用String 进行递归,没出现问题,现在想来,String作为不可变量,每次更改时其实都是重新申请了String对象,暗合值传递理念,只能说博主还是太年轻啊~~引以为鉴!