持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第1天,点击查看活动详情
组合总和
组合总和,指给你一个目标数据target,让你从一个整数数组candidates中选取不同的组合进行相加,使得数与目标数据相同,且同一个数据可以无限制重复被选取。我们的目标是,求出有几种组合情况并返回每种情况。
在该题目其实还有一个隐藏条件,就是每个整数数组都是都是按升序排序的。
解题思路
官方解法主要是回溯法,还有一个大佬用了回溯+剪枝法。这两个方法今天我们不细讲,以后找个机会写篇文章。
观察类似选取数据的题目时,我们需要找到一种逻辑上是有规律的、有逻辑的组合方式来选取数据。保证这种方式能够避免数据重复、数据冗余。如果想象力丰富的还可以把题目内容类比成生活中的某些事件,以便我们更好的找到他的特性。
我们可以把我们的目标数据total想像成一个桶,total的值就代表了桶的容量,把整数数组candidates里的数据想象成一瓶瓶不同容量的空瓶,他们从小到大依次排列好。我们的目标是先用空瓶装满水,然后再把装满水的空瓶倒入到桶中。
这样我们就把题目变成了一个可想象的、可yy的事件。对于拥有贪心思想的我而言,我肯定先用最大的瓶子来装水,这样装水的次数就少了。注意!瓶子是可重复使用的,因此我会先用最大的瓶子一直装,直到再倒一次桶会溢出时结束。这段可以用一行代码表示:
target / candidates[candidates.length - 1]
那么,桶还需要装入的水量就可以表示为:
target % candidates[candidates.length - 1]
你看,复杂的事物用代码来表达就会变得简单【虽然大多数时候是更加复杂】。在这里我要先让大家了解几个参数:
- rem[]数组,它代表刚好把桶装满,需要该水瓶的数量。例如rem[1]=2,就是要2个candidates[i]。
- mod,代表在注入水后,桶中还需注入的水量
回归正题,若桶还没满,我们只需要拿取容量最大的且比上一个瓶子要小的,同时用选中的瓶子装水不会使桶溢出的瓶子即可。
那么有没有一种可能,我是说可能,这样不断迭代下去直到用最小的瓶子也不能刚好装满桶? 那么我们就得回到前一步,用上一次装水的瓶子把桶里的水捞出来,此时桶还需装入的水量为:
//candidates[i]代表上一次的瓶子
mod = mod + candidates[i];
因为我们知道用较大的瓶子行不通了,所以就换到了较小的瓶子继续迭代。
经过反复循环迭代,就能在mod=0的时候知道瓶子的使用情况。将数据记录下来并继续循环迭代。
示例
经过了文字讲解,给大伙几个例子和图示理解一下。
示例 1:
输入:candidates = [2,3,6,7], target = 7
输出:[[2,2,3],[7]]
解释:
2 和 3 可以形成一组候选,2 + 2 + 3 = 7 。注意 2 可以使用多次。
7 也是一个候选, 7 = 7 。
仅有这两种组合。
代码
class Solution {
List<List<Integer>> ans = new ArrayList<>();
int[] rem;
public List<List<Integer>> combinationSum(int[] candidates, int target) {
rem = new int[candidates.length];
calculate(candidates,target,candidates.length);
return ans;
}
public void calculate(int[] candidates, int target, int range) {
//因为是升序排序,从后往前
for (int i = range - 1; i >= 0; i--) {
//代表当前数字最多可以被选入几次
rem[i] = target / candidates[i];
//代表被填充完后还剩下哪些部分需要填充
int mod = target % candidates[i];
//如果当前字段有多余的
while (rem[i] > 0) {
if(mod == 0){
//如果刚好取模为0
List<Integer> temp = new ArrayList<>();
for(int j = 0; j < candidates.length ; j++){
int numCount = rem[j];
//添加rem里记录的数据
while(numCount-- > 0){
temp.add(candidates[j]);
}
}
ans.add(temp);
}else{
calculate(candidates, mod, i);
}
//回到上一步
rem[i]--;
//重新计算需要的水量
mod += candidates[i];
}
}
}
}