(Java)LeetCode-40. Combination Sum II

本文介绍了一种使用回溯算法解决组合求和问题的方法,特别针对元素不可重复使用的场景,并通过排序和跳过重复元素的方式去除重复解。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Given a collection of candidate numbers (C) and a target number (T), find all unique combinations in C where the candidate numbers sums to T.

Each number in C may only be used once in the combination.

Note:

  • All numbers (including target) will be positive integers.
  • The solution set must not contain duplicate combinations.

For example, given candidate set [10, 1, 2, 7, 6, 1, 5] and target 8
A solution set is: 

[
  [1, 7],
  [1, 2, 5],
  [2, 6],
  [1, 1, 6]
]

这道题和前一题很像,只不过这题的数组里面的数只能用一次,而且会有重复。

我本来采用跟上一题一样的算法,代码都快写好了,又想到了一个更简便更直观的,就是正宗的回溯,感觉上一题的不够成熟,有点难读。

此题数组里重复数字,带来一个问题就是会得到重复的List,我之前的想法是用Set来去除重复,经过检验会大大拖慢速度,需要在算法中改进。后来百度了一下看了别人的代码,发现假设如果数组里有多个1的话,那么将第一个1放入list之后回溯会得到所有包含这个1的情况,那么就不再需要将后面的1再放入数组中再回溯了,从而去除了重复的情况。比如数组为[1,1,1,1,2],目标是3,那么将第一个1放入list后回溯,变成[1,1,1,2],目标是2,会得到两个数组[1,1][2],再加上第一个1,就是[1,1,1][1,2],这包含了所有的含有1的情况,不需再考虑后面的1了,从而避免重复数组。这是比较容易理解的,实际模拟一下算法运行过程即可。 

代码如下:

public class Solution {public List<List<Integer>> combinationSum2(int[] candidates, int target) {
		Arrays.sort(candidates);
		List<List<Integer>> result = new ArrayList<List<Integer>>();
		List<Integer> list = new ArrayList<Integer>();
		combinationSum(result, list, candidates, target, 0);
		return result;
    }
	
	private void combinationSum(List<List<Integer>> result, List<Integer> list, int[] candidates, int target, int index){

		for(int i = index; i < candidates.length; i++){
			int temp = candidates[i];
			if(temp == target){
				list.add(temp);
				result.add(new ArrayList<Integer>(list));
				list.remove(list.size()-1);
				break;
			}
			if(candidates[i] < target){
				list.add(candidates[i]);
				combinationSum(result, list, candidates, target - temp, i + 1);
				list.remove(list.size()-1);
				while(i < candidates.length-1 && candidates[i] == candidates[i+1]){
					i++;
				}
			}
			if(temp > target){
				break;
			}
		}
	}}





评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值