算法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]

https://leetcode.com/problems/combination-sum-iii/

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

https://leetcode.com/problems/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 = 4

The 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.

回溯法,第一位可能出现nums的每一种情况,第二位也可能出现nums的每一种情况。

class Solution:
    def combinationSum4(self, nums, target):
        """
        :type nums: List[int]
        :type target: int
        :rtype: int
        """
        total = [0]
        self.backtrace(total, [], nums, 0, target)
        return total[0]
    
    def backtrace(self, total, r, nums, s, target):
        if s==target:
            total[0] += 1
            return
        if s>target:
            return
        for i in range(len(nums)):
            r.append(nums[i])
            s += nums[i]
            #print(r, s)
            self.backtrace(total, r, nums, s, target)
            r.pop(-1)
            s -= nums[i]

代码超时,这样需要遍历所有情况。

nums=[1,2,3]  target=4 

假定组成target=4的组合最后一位数字为nums[2]=3,则 则该种情况有  comb(target-nums[2])

同理  可得   comb(4)=comb(target-nums[2])+comb(target-nums[1])+comb(target-nums[0])

comb[target] = sum(comb[target - nums[i]]), where 0 <= i < nums.length, and target >= nums[i].

class Solution:
    def combinationSum4(self, nums, target):
        """
        :type nums: List[int]
        :type target: int
        :rtype: int
        """
        if target==0:
            return 1
        res = 0
        for i in range(len(nums)):
            if target>=nums[i]:
                res += self.combinationSum4(nums, target-nums[i])
        return res

还是超时,这里面重复计算多次,因此可以用dp来保存中间结果,避免重复计算

生成一个长度为target+1的数组来保存组合数为某一值的数量comb

依次计算i=0,1,2.....target的种类数

对于每一种i==target,都需要遍历一遍给定数组nums

comb[i]=comb[i]+comb[i-nums[j]]

初始时comb[0]==1,最终返回comb[target]即可

class Solution:
    def combinationSum4(self, nums, target):
        """
        :type nums: List[int]
        :type target: int
        :rtype: int
        """
        comb = [0 for i in range(target+1)]
        comb[0] = 1
        for i in range(1, target+1):
            res = 0
            for j in range(len(nums)):
                if i>=nums[j]:
                    res = res + comb[i-nums[j]]
                    #print(res, i, j)
            #print(res, comb)
            comb[i] = res
        return comb[target]

https://leetcode.com/problems/palindrome-partitioning/

剑指offer回溯法题目总结

回溯法总结

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值