leetcode解题之 Combination Sum III java 版(组合求和III)

来源:互联网 发布:javascript拼图 编辑:程序博客网 时间:2024/05/22 06:53

216. Combination Sum III

Find all possible combinations of k numbers that add up to a numbern, given that only numbers from 1 to 9 can be used and each combination should be a unique set of numbers.

Example 1:

Input: k = 3, n = 7

Output:

[[1,2,4]]

Example 2:

Input: k = 3, n = 9

Output:

[[1,2,6], [1,3,5], [2,3,4]]

每个数字只能使用一次,升序排列,

public List<List<Integer>> combinationSum3(int k, int n) {List<List<Integer>> res = new ArrayList<List<Integer>>();List<Integer> tmp = new ArrayList<>();// 注意是从数字1开始dfsCore(res, 1, 0, tmp, n, k);return res;}private void dfsCore(List<List<Integer>> res, int curIdx, int sum, List<Integer> tmp, int n, int k) {if (sum > n)return;if (k < 0)return;if (sum == n && k == 0) {res.add(new ArrayList<Integer>(tmp));return;}// For循环每次从curIdx开始,避免返回到之前的元素for (int i = curIdx; i < 10; i++) {// 剪枝if (n < sum)return;sum += i;tmp.add(i);// 传入i+1//注意直接i++和在函数中使用i+1的区别i++;dfsCore(res, i, sum, tmp, n, k - 1);// 回溯i--;tmp.remove(tmp.size() - 1);sum -= i;}}

377. Combination Sum IV

Given an integer array with all positive numbers and no duplicates, find the number of possible combinations that add up to a positive integer target.

Example:

nums = [1, 2, 3]target = 4The possible combination ways are:(1, 1, 1, 1)(1, 1, 2)(1, 2, 1)(1, 3)(2, 1, 1)(2, 2)(3, 1)Note that different sequences are counted as different combinations.Therefore the output is 7.

Follow up:
What if negative numbers are allowed in the given array?
How does it change the problem?
What limitation we need to add to the question to allow negative numbers?

    一开始想到用DFS来做, 但是有个问题就是这种方式得到的答案各个数字排列是无序的, 也就是1, 3和3, 1这种只是一个答案, 然后又想把数字保存起来, 在得到一个答案的时候对这些数字再求一次总共排列的个数, 这种方式还有问题就是在求总排列个数的时候比如2, 1, 1三个加一起等于4, 总的排列个数即为(3!/2!), 但是当数字个数很多的时候阶乘太大, 根本无法计算.
    然后就想到可以用动态规划来做, 也是一个背包问题, 求出[1, target]之间每个位置有多少种排列方式, 这样将问题分化为子问题. 状态转移方程可以得到为:
    dp[i] = sum(dp[i - nums[j]]),  (i-nums[j] > 0);

   其中dp[i]表示生成数字i的所有可能的排列方式的个数。
    如果允许有负数的话就必须要限制每个数能用的次数了, 不然的话就会得到无限大的排列方式, 比如1, -1, target = 1;

超时版本

public int combinationSum4(int[] nums, int target) {Arrays.sort(nums);dfsCore(0, 0, nums, target);return count;}int count = 0;private void dfsCore(int curIdx, int sum, int[] nums, int target) {if (sum > target)return;if (sum == target)++count;// i从0开始,有点像排列,顺序不一样的属于不同元素for (int i = 0; i < nums.length; i++) {// 同一层次不能出现相同元素if (sum > target)return;sum += nums[i];// 不传入i+1 ,可以重复dfsCore(i, sum, nums, target);sum -= nums[i];}}

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++) {// 选取nums小于i的元素计算组合次数if (i >= nums[j]) {// 选取当前元素后,组合个数由剩余部分决定dp[i] += dp[i - nums[j]];}}}return dp[target];}

更新:

DFS+记忆化搜索算法,使用map去除不必的计算

//DFS+记忆化搜索public class Solution {Map<Integer, Integer> map = new HashMap<>();public int combinationSum4(int[] nums, int target) {int count = 0;if (nums == null || nums.length == 0 || target < 0)return 0;if (target == 0)return 1;if (map.containsKey(target))return map.get(target);for (int num : nums) {count += combinationSum4(nums, target - num);}map.put(target, count);return count;}}

参考:

39. Combination Sum

40. Combination Sum II

78. Subsets

90. Subsets II





0 0