1. 程式人生 > >Leetcode演算法——39、組合之和

Leetcode演算法——39、組合之和

給定一個無重複元素的陣列 candidates 和一個目標數 target,找到 candidates 中所有可以使數字之和等於 target 的組合。

candidates 中的數字可以無限制重複被選取。

備註:
陣列的元素和目標值都是正數。
答案中不能有重複組合。

示例:

Example 1:
Input: candidates = [2,3,6,7], target = 7,
A solution set is:
[
  [7],
  [2,2,3]
]

Example 2:
Input: candidates = [2,3,5], target = 8,
A solution set is:
[
  [2,2,2,2],
  [2,3,3],
  [3,5]
]

思路

可以使用分治法+回溯法。

既然不限制組合的大小、並且同一個數字可以被重複選取,那麼很容易將一個問題進行分解:比如陣列第一個元素為1,那麼目標是求一個組合相加等於5,這個問題可以轉化為求一個組合相加等於4,最後所有的組合結果都再加上一個1即可。

同理,陣列的所有位置的元素,都可以使用這個思路進行分治。

但是有一個問題,如果分解到最後,候選陣列中所有元素都比要求的和大,那麼就無法滿足要求。這時候應該知道,肯定是之前某一步,錯誤地將一個過大的數字加入了組合中,使得剩餘的目標值過小。因此,需要使用回溯法,依次將上一個所選元素修改為其他候選元素,如果所有其他候選元素都不滿足要求,則需要換上上一個元素,直至找到了那個過大的數字將其換掉。這就是回溯法。

python實現

def combinationSum(candidates, target):
    """
    :type candidates: List[int]
    :type target: int
    :rtype: List[List[int]]
    回溯法。
    從列表中選擇一個元素a,放入到結果池中。
    這樣,剩下的任務就是從陣列中挑選組合使得求和等於 target-a。
    因此,可以用遞迴方法繼續執行子任務。
    如果任務最後完不成,則將元素a換成下一個元素b,繼續執行新的子任務。
    """
    
    sorted_candidates =
sorted(candidates) result_list = [] def fun_rec(cur_result, remain): ''' 找到可以滿足相加等於remain的一個組合, 與字首cur_result連線, 放入到result_list中 ''' if remain == 0: # 剩餘恰好為0 result_list.append(cur_result) return for i in sorted_candidates: if i > remain: # 之後的更大,更不會滿足要求,不必繼續迴圈 break elif not cur_result or i >= cur_result[-1]: # 避免重複 fun_rec(cur_result + [i], remain - i) fun_rec([], target) return result_list if '__main__' == __name__: candidates = [2,3,5] target = 8 print(combinationSum(candidates, target))