leetcode combination-sum题集

这次对以上组合问题进行总结。题的主旨是对一个数组找到所有和为target的组合形式。题目要求不一,下面一一介绍。

39. 组合总和

数组无重复,每个数字可以被无限次使用,要求返回所有可能的情况(顺序不一样视作一种)。用dfs。

思路:

  • 先排序,然后进行遍历。
  • 和超过target返回。
  • target减到0时把数组加进去。
  • 注意去重,比如[1,2]和[2,1]设置加入数必须比之前所有加入的大。
class Solution(object):
    def __init__(self):
        self.res = []

    def combinationSum(self, candidates, target):
        """
        :type candidates: List[int]
        :type target: int
        :rtype: List[List[int]]
        """
        self.res = []
        candidates.sort()
        self.dfs(candidates, target, [])
        return self.res
    def dfs(self, candidates, val, temp):
        if 0 == val:
            self.res.append(temp)
            return
        if val < 0:
            return
        for i in range(len(candidates)):
            if candidates[i] > val: return
            if len(temp) > 0 and candidates[i] < temp[-1]:
                continue
            self.dfs(candidates, val - candidates[i], temp + [candidates[i]])
        return

40. 组合总和 II

数组有重复,每个数字只能被使用一次,要求返回所有可能的情况(顺序不一样视作一种)。用dfs。

思路:

  • 先排序,然后进行遍历。
  • 和超过target返回,target减到0时把数组加进去。
  • 注意去重,比如[1,2]和[2,1]设置加入数必须比之前所有加入的大。
  • 此外,因为有重复,所以每次额外传一个参数,表示上一个用到的索引,在这个索引之前(包括这个)都不再进行遍历。
class Solution(object):
    def combinationSum2(self, candidates, target):
        """
        :type candidates: List[int]
        :type target: int
        :rtype: List[List[int]]
        """
        res = []
        candidates.sort()
        #print candidates
        def dfs(val, path, lastind):
            if val == 0:# and path not in res:
                res.append(path)
                return
            last = None
            for i in range(len(candidates)):
                if len(path) > 0 and (candidates[i] < path[-1] or candidates[i] == path[-1] and i <= lastind): #改动
                    continue
                if candidates[i] > val:break
                if candidates[i] == last:#改动
                    continue
                dfs(val - candidates[i], path + [candidates[i]], i)
                last = candidates[i]
            return
        dfs(target, [], -1)
        return res

216. 组合总和 III

数组被指定为range(1,10),但是要求返回到数组长度都为指定长度k。要求返回所有可能的情况(顺序不一样视作一种)。用dfs。

思路:

  • 不需要排序,进行遍历。
  • 和超过target返回。
  • target减到0且长度等于k时把数组加进去。
  • 注意去重,比如[1,2]和[2,1]设置加入数必须比之前所有加入的大。
class Solution(object):
    def combinationSum3(self, k, n):
        """
        :type k: int
        :type n: int
        :rtype: List[List[int]]
        """
        nums = range(1, 10)
        res = []
        def dfs(val, path, c):
            if len(path) == c:
                if val == 0:
                    res.append(path)
                return
            for i in range(len(nums)):
                if len(path) > 0 and nums[i] <= path[-1]:
                    continue
                if nums[i] > val:
                    return
                dfs(val - nums[i], path + [nums[i]], c)
            return
        dfs(n, [], k)
        return res

377. 组合总和 Ⅳ

数组无重复,每个数字可以被无限次使用,要求返回所有可能的情况(顺序不一样视作不同)的数量。用dfs。

思路:

  • 顺序不同视为不同结果,比如[1,1,2],[1,2,1],[2,1,1]为三种不同的情况。
  • 因为题只要求返回数量,计数型一般是用递推来做。因为dfs需要更多的复杂度。
  • 观察发现递推关系为dp[i] += dp[i - num] for num in nums,即每个数而言,都可以拆分成数组中的一个数和之前dp的另一个数,比如[1,2,4],target=4的情况,dp[4]就可以拆分为1和dp[3]的组合,2和dp[2]的组合,4和dp[0]的组合。
  • 这里需要注意dp[0]=1表示空集和数本身的组合,只有一种情况。
class Solution(object):
    def combinationSum4(self, nums, target):
        """
        :type nums: List[int]
        :type target: int
        :rtype: int
        """
        dp = [1]
        nums.sort()
        for i in range(1, target + 1):
            temp = 0
            for j in range(len(nums)):
                if nums[j] > i:
                    break
                temp += dp[i - nums[j]]
            dp.append(temp)
            #print dp
        return dp[-1]

总结

求数量一般按照递推思想来做,而求所有可能情况一般是dfs。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值