leetcode 面试题40. 组合总和 II

2020/3/19  打卡

题目

给定一个数组 candidates 和一个目标数 target ,找出 candidates 中所有可以使数字和为 target 的组合。
candidates 中的每个数字在每个组合中只能使用一次。

  说明:

  所有数字(包括目标数)都是正整数。
  解集不能包含重复的组合。
  示例 1:

  输入: candidates = [10,1,2,7,6,1,5], target = 8,
  所求解集为:
  [
    [1, 7],
    [1, 2, 5],
    [2, 6],
    [1, 1, 6]
  ]
  示例 2:

  输入: candidates = [2,5,2,1,2], target = 5,
  所求解集为:
  [
    [1,2,2],
    [5]
  ]

思路

这里有个 主要的问题是  ‘candidates 中的每个数字在每个组合中只能使用一次’,所以这里很大的牵扯到去重的问题。
本题难点:candidates=[1,7,1],target=8,,,那么[1,7]和[7,1]重复

使用回溯+剪枝的算法。  在三步走过程中,融入对两步剪枝操作的判别。

1.特判,若candidates为空,则返回[]
2.回溯函数helper(),传入参数:下一加和索引ii,当前已加和数组tmp,下一目标target
    (1)若target==0,说明当前和满足条件,将当前加和数组tmp加入res,并return。
    (2)剪枝 因为已经将candidates排序,所以当下一目标小于下一待加和数时,return。
         并且当下一待加和索引i==n时,return。(为了防止数组越界,将条件i==n放在target<candidates[i]之前,进行截断。)
    (3)对于j遍历区间[i,n),根据条件j>iandcandidates[j]==candidates[j−1](为了防止数组越界,首先保证j>i,判断是否和
    上一元素相等),分为以下两种情况:
        *若满足条件j>i and candidates[j]==candidates[j-1],则跳过,避免出现重复解,同时也进行了剪枝。
        *否则,执行helper(j+1,tmp+[candidates[j]],target−candidates[j])
3.执行helper(0,[],target),并返回res

代码

时间复杂度:O(n!) 空间复杂度:O(n)

class Solution:
    def combinationSum2(self, candidates, target):
        # 边界条件
        if(not candidates):
            return []
        # 进行预排序操作
        n=len(candidates)
        candidates.sort()
        res=[]

        def helper(i,tmp,target):
            # 当前和满足条件,将当前加和数组tmp加入res,并return
            if(target==0):
                res.append(tmp)
                return
            #  对于 越界操作 无效解的去除。   因为是排序过的,所以可以直接判别出 余值的满足情况。
            if(i==n or target<candidates[i]):
                return

            for j in range(i,n):
                #用于避免出现重复解 的剪枝操作
                if(j>i and candidates[j]==candidates[j-1]):
                    continue
                # i是新的dfs的起点, tmp存储暂时路径,最后是余值。
                helper(j+1,tmp+[candidates[j]],target-candidates[j])

        # 外部调动dfs搜索。
        helper(0,[],target)
        return res

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值