Java实现 LeetCode 组合总和(I-IV)(dfs)

共同特征:都是用一个数组凑出一个目标数,每道题的限制有些不同,都能够用 dfs+回溯+剪枝。传递一个sum参数,判断能否将新的数字加入到ans序列中。

39.组合总和
给定一个无重复元素的数组 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]
]

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/combination-sum
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

class Solution {
    public List<List<Integer>> combinationSum(int[] candidates, int target) {
        List<List<Integer>> ans = new LinkedList<List<Integer>>();
		List<Integer> list = new LinkedList<>();
		Arrays.sort(candidates);//做一个排序,当前结点的无法组成目标值,那么比他大的数也不可能组成
		dfs(ans,list,target,candidates,target,0);
		return ans;
	}
	private void dfs(List<List<Integer>> ans, List<Integer> list, int sum, int[] candidates, int target, int index) {
		if(sum == 0) {
			ans.add(new ArrayList<Integer>(list));
		}
		for(int i = index; i < candidates.length; i++) {
			if(sum - candidates[i] < 0) {
				break;
			}
			list.add(candidates[i]);
			dfs(ans,list,sum-candidates[i],candidates,target,i);
			list.remove(list.size()-1);
		}
    }
}

40.组合总和II
给定一个数组 candidates 和一个目标数 target ,找出 candidates 中所有可以使数字和为 target 的组合。

candidates 中的每个数字在每个组合中只能使用一次。

说明:

所有数字(包括目标数)都是正整数。
解集不能包含重复的组合。
示例 1:

输入: candidates = [10,1,2,7,6,1,5], target = 8,
所求解集为:
[
[1, 7],
[1, 2, 5],
[2, 6],
[1, 1, 6]
]
示例 2:

输入: candidates = [2,5,2,1,2], target = 5,
所求解集为:
[
[1,2,2],
[5]
]

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/combination-sum-ii
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

class Solution {
    public List<List<Integer>> combinationSum2(int[] candidates, int target) {
       List<List<Integer>> ans = new LinkedList<List<Integer>>();
		List<Integer> list = new LinkedList<>();
		
		Arrays.sort(candidates);
		dfs(ans,list,candidates,target,target,0);
		return ans;
	}
	private void dfs(List<List<Integer>> ans, List<Integer> list, int[] candidates, int target, int sum, 
			int k) {
		if(sum == 0) {
			ans.add(new LinkedList<>(list));
		}
		for(int i = k; i < candidates.length; i++) {
			if(sum-candidates[i] < 0) {
					break;
				}
				if(i > k && candidates[i] == candidates[i-1]) {//处理重复的情况
					continue;
				}
				
				list.add(candidates[i]);
				dfs(ans,list,candidates,target,sum-candidates[i],i+1);
				
				list.remove(list.size()-1);
			
		
        }
    }
}

216.组合总和III
找出所有相加之和为 n 的 k 个数的组合。组合中只允许含有 1 - 9 的正整数,并且每种组合中不存在重复的数字。

说明:

所有数字都是正整数。
解集不能包含重复的组合。
示例 1:

输入: k = 3, n = 7
输出: [[1,2,4]]
示例 2:

输入: k = 3, n = 9
输出: [[1,2,6], [1,3,5], [2,3,4]]

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/combination-sum-iii
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

class Solution {
    public List<List<Integer>> combinationSum3(int k, int n) {
        List<Integer> list = new ArrayList<Integer>();
		List<List<Integer>> ans = new ArrayList<>();
		dfs(n,list,ans,k,1);
		return ans;
    }
	private void dfs(int n, List<Integer> list, List<List<Integer>> ans, int k, int start) {
		if(n == 0) {
			if(list.size() == k) {
				ans.add(new ArrayList<>(list));
			}
		}
		for(int i = start; i <= 9; i++) {
			if(n-i >= 0 && list.size() < k && !list.contains(i)) {
				list.add(i);
				dfs(n-i, list, ans, k, i+1);
				list.remove(list.size()-1);
			}
		}
    }
}

377.组合总和 IV
给定一个由正整数组成且不存在重复数字的数组,找出和为给定目标正整数的组合的个数。

示例:

nums = [1, 2, 3]
target = 4

所有可能的组合为:
(1, 1, 1, 1)
(1, 1, 2)
(1, 2, 1)
(1, 3)
(2, 1, 1)
(2, 2)
(3, 1)

请注意,顺序不同的序列被视作不同的组合。

因此输出为 7。
进阶:
如果给定的数组中含有负数会怎么样?
问题会产生什么变化?
我们需要在题目中添加什么限制来允许负数的出现?

致谢:
特别感谢 @pbrother 添加此问题并创建所有测试用例。

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/combination-sum-iv
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

这道用的动态规划

class Solution {
    public int combinationSum4(int[] nums, int target) {
        int[] dp = new int[target+1];
		dp[0] = 1;

		for(int i = 1; i <= target; i++) {
			for(int j = 0; j < nums.length; j++) {
				if(i >= nums[j] && dp[i-nums[j]] > 0) {
					dp[i] += dp[i-nums[j]];
				}
			}
		}
		return dp[target];
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值