算法圖解——組合求和( Combination Sum)


 組合求和( Combination Sum)

1. 題目描述

Given an array of distinct integers candidates and a target integer target, return a list of all unique combinations of candidates where the chosen numbers sum to target. You may return the combinations in any order.The same number may be chosen from candidates an unlimited number of times. Two combinations are unique if the frequency of at least one of the chosen numbers is different.It is guaranteed that the number of unique combinations that sum up to target is less than 150 combinations for the given input.

翻譯過來就是:【還是建議大家先看英文的自己理解一下再看翻譯】

給定一個無重復整數數組candidates 和一個目標整數 target,返回一個唯一的候選組合的列表,其中所選列表中數字之和與目標數相等。返回的列表可以任意順序。

同一個數可從候選人中無限次選出。如果所選數字中至少一個的頻率不同,則兩個組合是唯一的。

對於給定的輸入,保證總計到目標的唯一組合數少於150個組合。


2. 示例

示例1:

Input: candidates = [2,3,6,7], target = 7
Output: [[2,2,3],[7]]
Explanation:
2 and 3 are candidates, and 2 + 2 + 3 = 7. Note that 2 can be used multiple times.
7 is a candidate, and 7 = 7.
These are the only two combinations.

示例2:

Input: candidates = [2,3,5], target = 8
Output: [[2,2,2,2],[2,3,3],[3,5]]

示例3:

Input: candidates = [2], target = 1
Output: []

示例4:

Input: candidates = [1], target = 1
Output: [[1]]

示例5:

Input: candidates = [1], target = 2
Output: [[1,1]]

 

3. 要求

  • 1 <= candidates.length <= 30
  • 1 <= candidates[i] <= 200
  • All elements of candidates are distinct【數組元素都是不一樣的】.
  • 1 <= target <= 500

4. 解題思路 

此題其實類似於背包問題,可以利用貪心的思想。先排序,然后從第一個元素遍歷,當把元素 sum[i] 加入到列表 arr 中后(求和列表),剩下的問題其實就是一個子問題——求數組num中和為 target-sum[i] 的子問題。但是 sum[i] 也可能不是求和數組 arr 中的元素,即有了sum[i] 后就不可能組合成target之和。故在遞歸后,還得需要把該元素給回退掉。

即:

arr.add(nums[i]);  //添加元素
search(res,arr,nums,target-nums[i],i);  //遞歸
arr.remove(arr.size()-1);//如果不滿足的話,還可以退回。

 

5. 實現:

 全文代碼實現:

class Solution {
    public List<List<Integer>> combinationSum(int[] nums, int target) {
        ArrayList<List<Integer>> res = new ArrayList<List<Integer>>();
        Arrays.sort(nums);//背包問題
        
        search(res,new ArrayList<Integer>(),nums,target,0);
        return res;
    }
    private void search(ArrayList<List<Integer>> res,ArrayList<Integer> arr,int[] nums,int target,int index){
        //待求和為0時
        if(target==0){
            res.add(new ArrayList<Integer>(arr));
            return;
        }
        //待求和<0時返回空。因為1 <= candidates[i] <= 200,且1 <= target <= 500
        if(target<0)  return;
        
        for(int i=index;i<nums.length;i++){
            if(target-nums[i]>=0){
                arr.add(nums[i]);
                search(res,arr,nums,target-nums[i],i);  //遞歸,注意這里是i 不是i++;
                arr.remove(arr.size()-1);//如果不滿足的話,還可以退回。
            }else
                break;
        }
    }
}

 

 

6. 拓展:

題目上說的是求和數組 arr 中的元素可以重復,如示例1,2:

Input: candidates = [2,3,6,7], target = 7
Output: [[2,2,3],[7]]
Input: candidates = [2,3,5], target = 8
Output: [[2,2,2,2],[2,3,3],[3,5]]

那么,如果該要求改為不可以重復,該如何解呢?

Input: candidates = [2,3,6,7], target = 7
Output: [[7]]

Input: candidates
= [2,3,5], target = 8 Output: [[3,5]]

其實,我們只需要在添加元素 nums[i] 到arr 中后,再把原數組nums 中對應的元素給去掉就行,然后形成子問題,再之后再恢復過來即可。

 

 

 

 

 

參考致謝:

1、LeetCode Top 100 高頻算法題39. Combination Sum

 

 

Over......

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM