2020年9月10日组合总和 II combinationSum2
class Solution {
public List<List<Integer>> combinationSum2(int[] candidates, int target) {
}
}
解题思路:
今天这道题和昨天那道非常类似,区别在于今天这个是不允许重复,但是不允许重复的话这道题会更加简单一些,因为这就变成了单纯的递归+回溯的算法了。
还是昨天的思路,递归的三大关键:
1,流程逻辑
怎么把大问题转变为小问题来解决?
很简单,我们求[1,2,3]能否组成6,那么可以转换为,6-1=[2,3]能否组成5,6-2=[1,3]能否组成4,6-3=[1,2]能否组成2。
2,参数传递
参数的话接收的是一个数组,和要求的值,传出的是能组成target的数组。
3,什么时候停止
target小于等于0的时候应该就需要停止,小于0表示无法组成了,等于0的话是刚好能够组成,在返回值链表中加入一个整形数组,数组中只有一个整数就是当前整数。
代码实现:
在编码过程中逐渐发现了里面埋藏的坑,由于存在重复的数,所以应该先对数组进行处理
思路出现了问题,想在之前的基础上修改规则就能达到今天的效果,实际上这种强行凑出的方法效率非常低,我为了能够不重复,先进行了一次冒泡排序。
boolean flag=false;
public List<List<Integer>> combinationSum2(int[] candidates, int target) {
//先进行排序
if (!flag)
{
paixv(candidates);
}
int len=candidates.length;
//复制数组
int[] newcandidates=new int[len];
System.arraycopy(candidates,0 ,newcandidates ,0 ,len );
List<List<Integer>> res=new ArrayList<>();
for (int i=0;len>0;){
///求得差
int cha=target-newcandidates[i];
//如果得到差为0,则在返回值中加入
if (cha==0){
List<Integer> list=new ArrayList<>();
list.add(newcandidates[i]);
res.add(list);
}
//如果小于0,说明不会成立,直接跳过
//否则开始递归
else if (cha>0){
int[] thiscandidates=new int[len-1];
System.arraycopy(newcandidates,1 ,thiscandidates ,0 ,len-1 );
//递归
List<List<Integer>> lists = combinationSum2(thiscandidates, cha);
//在头部添加一个当前元素
for (List<Integer> list : lists) {
list.add(0,newcandidates[i]);
}
res.addAll(lists);
}
//删除掉这一个元素
int val=newcandidates[i];
do {
int[] newcandidates2=new int[len-1];
System.arraycopy(newcandidates,1 , newcandidates2,0 ,len-1);
len=len-1;
newcandidates=newcandidates2;
}while (len!=0&&newcandidates[0]==val);
}
return res;
}
public void paixv(int[] array){
int len=array.length;
for (int i=0;i<len;i++){
for (int j=0;j<len-1-i;j++){
if (array[j]>array[j+1]){
int val=array[j];
array[j]=array[j+1];
array[j+1]=val;
}
}
}
}