1. 程式人生 > >演算法46--回溯法3--Combination Sum1,2,3,4

演算法46--回溯法3--Combination Sum1,2,3,4

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

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

Note:

  • All numbers (including target
    ) will be positive integers.
  • The solution set must not contain duplicate combinations.

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

假設符合條件的集合長度為N,首先考慮第一位,第一位可以取值nums所有元素,統計r中已有元素的和,

當s==target時記錄此時r,返回即可,

當s>target返回即可

否則說明s<target  則應繼續尋找下一個元素,使用start來標識當前已經到那個數字作為最終結果的開始尋找點。

以2, 3, 6, 7為例,第一個數字可以取2,3,6,7

第一個數字取2時,第二個數字    2,  3,  6,   7

第一個數字取3時,第二個數字   3, 6,  7     如果第二個數字從第一個數字開始取,則會產生重複,因此應該從第二個數字開始取。

class Solution:
    def combinationSum(self, candidates, target):
        """
        :type candidates: List[int]
        :type target: int
        :rtype: List[List[int]]
        """
        rr=[]
        candidates.sort()
        self.backtrace(rr, [], 0, candidates, target, 0)
        return rr

    def backtrace(self, rr, r, s, candidates, target, start):
        if s==target:
            rr.append(r.copy())
            return
        if s>target:
            return
        for i in range(start, len(candidates)):
            r.append(candidates[i])
            s += candidates[i]
            self.backtrace(rr, r, s, candidates, target, i)
            s -= candidates[i]
            r.pop(-1)

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

Each number in candidates may only be used once in the combination.

Note:

  • All numbers (including target) will be positive integers.
  • The solution set must not contain duplicate combinations.

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

每個數字只能用一次,將陣列升序排列,這樣相同的數字便會相鄰,r中存放所有可能的試探組合

考慮第一位數字,可以放入陣列所有數字,然後依據s與target來進行判斷

若s<target 考慮第二位數字,首先若i>start  and nums[i-1]==nums[i]說明r中已經取過nums[i-1]的值,因此nums[i]可以直接跳過,否則會重複,進行下一次遍歷從start+1開始,每一個數字只能用一次,依次不能繼續從start開始。

class Solution:
    def combinationSum2(self, candidates, target):
        """
        :type candidates: List[int]
        :type target: int
        :rtype: List[List[int]]
        """
        rr=[]
        candidates.sort()
        self.backtrace(rr, [], 0, candidates, target, 0)
        return rr
        
    def backtrace(self, rr, r, s, candidates, target, start):
        if s == target:
            rr.append(r.copy())
            return
        if s > target:
            return
        for i in range(start, len(candidates)):
            if i>start and candidates[i-1]==candidates[i]:
                continue
            r.append(candidates[i])
            #print(r)
            s += candidates[i]
            #print(s)
            self.backtrace(rr, r, s, candidates, target, i+1)
            r.pop(-1)
            s -= candidates[i]

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

Note:

  • All numbers will be positive integers.
  • The solution set must not contain duplicate combinations.

Example 1:Input: k = 3, n = 7 Output: [[1,2,4]]

回溯法   最終集合長度為k,和為7   考慮第一位取值範圍 1--9     當第一位確定時,第二位的取值是除去第一位的1--9剩餘數字

遍歷順序 

1   12    123   1234    12345  ....     8    89    9

回溯法提供了對於集合的某種遍歷順序,每取一種組合方式,都要對於該種取值集合進行判斷是否符合條件,符合直接儲存返回,若已超出臨界條件並且繼續考慮下一位肯定不符合條件則直接返回,如果條件達不到則進行下一位的考慮,增加集合r的取值,進行遞迴判斷。

class Solution:
    def combinationSum3(self, k, n):
        """
        :type k: int
        :type n: int
        :rtype: List[List[int]]
        """
        rr=[]
        self.backtrace(rr, [], 0, k, 1, n)
        return rr
        
    def backtrace(self, rr, r, s, k, start, n):
        if len(r)==k and s==n:
            rr.append(r.copy())
            return        
        for i in range(start, 10):
            r.append(i)            
            s += i
            #print(r, i, s)
            self.backtrace(rr, r, s, k, i+1, n)
            r.pop(-1)
            s -= i

優化如下:加入提前終止條件:

class Solution:
    def combinationSum3(self, k, n):
        """
        :type k: int
        :type n: int
        :rtype: List[List[int]]
        """
        rr=[]
        self.backtrace(rr, [], 0, k, 1, n)
        return rr
        
    def backtrace(self, rr, r, s, k, start, n):
        if len(r)==k and s==n:
            rr.append(r.copy())
            return
        
        if s>n:
            return
        if len(r)>k:
            return
        if len(r)==k and s!=n:
            return
        
        for i in range(start, 10):
            r.append(i)            
            s += i
            #print(r, i, s)
            self.backtrace(rr, r, s, k, i+1, n)
            r.pop(-1)
            s -= i

劍指offer回溯法題目總結

回溯法總結