`
frank-liu
  • 浏览: 1666846 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

leetcode: Combination Sum

 
阅读更多

问题描述:

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

The same repeated number may be chosen from C unlimited number of times.

Note:

  • All numbers (including target) will be positive integers.
  • Elements in a combination (a1a2, … , ak) must be in non-descending order. (ie, a1 ≤ a2 ≤ … ≤ ak).
  • The solution set must not contain duplicate combinations.

 

For example, given candidate set 2,3,6,7 and target 7
A solution set is: 
[7] 
[2, 2, 3] 

 

原问题链接:https://leetcode.com/problems/combination-sum/

 

问题分析

方法一

  这个问题是给定一个数组,里面的元素可以重复选择。对于一个给定的目标数字,需要求数组里所有若干个数相加等于该目标数字的组合。由于题目的要求组合的元素必须是不能递减的顺序。所以需要一开始对这个数组排序。剩下的就是要来找若干个数使得它们的和等于目标数字。

  该怎么去找呢?对于给定的数组candidates和我们的目标值target。假设我们取了candidates里面位置i的元素的值来凑这个target。如果target > candidates[i],这就说明我们这个数字是可以加进来,不过接下来要考虑剩下的部分组成target - candidates[i]的问题。对于其他情况来说如果target < candidates[i],很明显,这种情况不符合我们的要求,我们就要返回。而如果target == candidates[i]呢,则表示我们正好构成了一个结果,需要将所有拼凑的数字返回。

  既然这里提到我们要拼凑这些数字来让它们等于target,并且要求将这些数字最终返回。所以在实现的时候应该考虑用一个List来保存每次符合条件的数字。另外,在前面发现要进一步递归的时候,该怎么来做下一步的递归呢?结合前面题目的要求,后面的取值不能小于前面的值,所以递归的时候下一步只能从i及i后面的元素来取。

  按照这种思路实现的代码如下:

 

public class Solution {
    public List<List<Integer>> combinationSum(int[] candidates, int target) {
        List<List<Integer>> ret = new LinkedList<List<Integer>>();
        Arrays.sort(candidates);
        recurse(new ArrayList<Integer>(), target, candidates, 0, ret);
        return ret;
    }
    
    private void recurse(List<Integer> list, int target, int[] candidates, int index, List<List<Integer>> ret) {
        if (target == 0) {
            ret.add(list);
            return;
        }
        for(int i = index; i < candidates.length; i++) {
            int newTarget = target - candidates[i];
            if(newTarget >= 0) {
                List<Integer> copy = new ArrayList<Integer>(list);
                copy.add(candidates[i]);
                recurse(copy, newTarget, candidates, i, ret);
            } else
                break;
        }
    }
}

 

 

方法二

    其实,前面的问题描述里头已经有一个很明显的痕迹。就是要求里面若干个数的和使得它们等于target。对于这个问题来说有一个递归的思路,就是假设target大于candidates里面的若干个数。那么这个问题就可以进一步转化成target减去这些值的递归子问题。因为这里一个问题可以递归成多个子问题。而且很多问题有可能是重叠的。这就很容易让人想到动态规划的思路。

  针对这个问题,动态规划的大致套路就是首先定义一个target长度的数组或者集合,用来保存它们递归过程中间的值。然后再从数值1到target来逐步遍历构建这个数组。这种思路的伪码实现如下:

 

public List<List<Integer>> combinationSum(int[] candidates, int target) {
        List<List<Integer>>[] dp = (List<List<Integer>>[]) new Object[target + 1];
        for(int i = 1; i <= target; i++) {
            for(int j = 0; j < candidates.length && candidates[j] <= i; j++) {
                dp[i] = merge(dp[i - candidates[j]], dp[candidates[j]]);
            }
        }
        return dp[target];
    }

   上述的伪码只是做了一个大致的描述。在实际的实现中因为java中不能直接声明泛型的数组,还是需要做一些变动。另外,对于两个部分结果的合并也有很多细节需要考虑。我们需要将candiates[j]的值加到原来列表里的每个元素里去。当然,还是要考虑过滤掉candidates[j]大于里面元素第一个成员的情况。

  按照这个思路,另外一种实现的代码如下:

 

public class Solution {
    public List<List<Integer>> combinationSum(int[] cands, int t) {
        Arrays.sort(cands); // sort candidates to try them in asc order
        List<List<List<Integer>>> dp = new ArrayList<>();
        for (int i = 1; i <= t; i++) { // run through all targets from 1 to t
            List<List<Integer>> newList = new ArrayList(); // combs for curr i
            // run through all candidates <= i
            for (int j = 0; j < cands.length && cands[j] <= i; j++) {
                // special case when curr target is equal to curr candidate
                if (i == cands[j]) newList.add(Arrays.asList(cands[j]));
                // if current candidate is less than the target use prev results
                else for (List<Integer> l : dp.get(i-cands[j]-1)) {
                    if (cands[j] <= l.get(0)) {
                        List cl = new ArrayList<>();
                        cl.add(cands[j]); cl.addAll(l);
                        newList.add(cl);
                    }
                }
            }
            dp.add(newList);
        }
        return dp.get(t-1);
    }
}

 

 

总结

     求若干个数字的和等于目标数字,其实其解法有好几种。比如递归法,或者深度优先遍历法或者动态规划法。重点是不同方法的思路和一些结果合并的细节。

 

分享到:
评论

相关推荐

    gasstationleetcode-Leetcode:力码

    Leetcode\combination sum(39).swift Leetcode\count number of team(1395).swift Leetcode\counting bits(338).swift Leetcode \find 数组中的所有重复项(442).swift Leetcode\find peak element(162).swift ...

    leetcode打不开-leetcode:leetcode

    leetcode打不开Leetcode Note Tips Tip1: Two pointer for sorted array (#Array 1. Two Sum) Tip2: Sum[i:j] = Sum[0:j] - Sum[0:i] for continuous array (# Array 560. Subarray Sum Equals K) Tip3: Knapsack ...

    leetcode530-Leetcode:新的开始

    leetcode 530 力码 全部的: 易(173/237+x) 中(144/437+x) 硬(4/x) 问题 1.Two Sum(dict) 7.(跳过)(数学) 9.(跳过)(串串技巧) 11.盛水最多的容器 12.(跳过)(问题不好) 13.(跳过)(蛮力) 14.(跳过)...

    leetcode怎么计算空间复杂度是指-LeetCode-Solution:我的第一个LeetCode解决方案

    leetcode怎么计算空间复杂度是指 LeetCode-Solution my first solution of LeetCode 2015-5-7 Problem 95,98(80 already!) 我经常在递归的结束地方忘记return!!! 题型一:经典暴力递归:(里面涉及到重复不重复的...

    leetcode怎么销号-LeetCode-Solutions:我自己的LeetCode解决方案

    leetcode怎么销号 LeetCode-Solutions :green_heart:My own LeetCode solutions No. Problem LeetCode 力扣 Python Go Solution Difficulty Tag 0017 Letter Combinations of a Phone Number Medium 回溯、暴力 0034...

    leetcode316-leetcode_problems:LeetCode刷题记录

    Combination Sum Description 给一组candidates (list of int)和target (int),求使用candidates内数字组合,让总和等于target的所有组合。 candidates内的数字皆不同 candidates内的数字可以重复使用无限次 ...

    leetcode2sumc-Leetcode_imp_C:Leetcode在C上的实现

    leetcode 2 和 c Leetcode_imp_C Leetcode 在 C 上的实现 大批: leetcode_0001_two_sum.c leetcode_0011_max_area.c leetcode_0015_three_sum.c ...leetcode_0039_combination_sum.c 40 leetcode_0041_first_miss

    數位之和leetcode-leetcode-cpp:我的LeetCodeC++答案

    sum: 39, 40, 216 - palindrome partitioning - regex - sudoku solver: 37 排序 - merge sort - quick sort - insertion sort - selection sort - counting sort 位操作 - find the only element which exists once...

    leetcode2-LeetcodeNotes:LeetCode解决方案和一切

    leetcode 2 Useful Links ...Sum], [17 Phone Num] [] BFS [] [] [] DP , [53 max subarray], , [96 DP | BST], , [] [] Binary Search , , [74 2D matrix] [] Slicing Window / Two Pointers [918 Ma

    Coding Interview In Java

    leetcode Java 246 題目及解答 (英文) Contents 1 Rotate Array in Java 15 2 Reverse Words in a String II 19 3 Evaluate Reverse Polish Notation 21 4 Isomorphic Strings 25 5 Word Ladder 27 6 Word Ladder ...

    leetcode2sumc-CTCI:CTCI

    combinationSum ( self , candidates , target ): def backtrack ( tmp , start , end , target ): if target == 0 : ans . append ( tmp [:]) elif target &gt; 0 : for i in range ( start , end ): tmp . append ( ...

    leetcode296-leetcode-in-py-and-go:Go中的Leetcode

    第 296 章PY 和 GO 中的 Leetcode 我在 Python Golang ...Leetcode ...40:combination-sum-ii:传递最后选择的索引 41:先缺失正,交换 42:只是提醒:块 - 垃圾箱 43:多字符串,i+j,i+j+1 44:通配符

    leetcode最大蓄水量-leetcode_note_book:leetcode题目分类及刷题总结

    CombinationSum 组合之和 完成 LinkedList 题目 说明 状态 AddTwoNumber 两数相加 完成 SwapPairs 两两交换链表中的节点 完成 String 题目 说明 状态 LongestSubstring 最长子串 完成 LongestPalindrome 最长回文...

    leetcode题库-little-algorithm:LeetCode题目参考代码与详细讲解,公众号《面向大象编程》文章整理

    leetcode题库 Little Algorithm 从 2020 年初开始,我在公众号《面向大象编程》上发表面试算法、LeetCode 题解相关文章,至今收获不少好评。此仓库是公众号内容的补充,包括公众号文章涉及到的题目的参考代码,以及 ...

    对python append 与浅拷贝的实例讲解

    def combinationSum(self, candidates, target): """ :type candidates: List[int] :type target: int :rtype: List[List[int]] """ result,temp = [],[] self.combinationSumRecu(sorted(candidates),...

    cpp-算法精粹

    Combination Sum III Generate Parentheses Sudoku Solver Word Search 总结 分治法 Pow(x,n) Sqrt(x) 贪心法 Jump Game Jump Game II Best Time to Buy and Sell Stock Best Time to Buy and Sell Stock II Longest...

Global site tag (gtag.js) - Google Analytics