LeetCode 40 组合总和 II NC46 加起来和为目标值的组合(二)

给定一个数组 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]
]

解题思路:

递归。

由于我们需要求出所有和为 target 的组合,并且每个数只能使用一次,因此我们可以使用递归 + 回溯的方法来解决这个问题:

我们用 dfs(pos,rest) 表示递归的函数,其中 pos 表示我们当前递归到了数组 candidates 中的第 pos 个数,而 rest 表示我们还需要选择和为 rest 的数放入列表作为一个组合;

对于当前的第 pos 个数,我们有两种方法:选或者不选。如果我们选了这个数,那么我们调用 dfs(pos+1,rest−candidates[pos]) 进行递归,注意这里必须满足 rest≥candidates[pos]。如果我们不选这个数,那么我们调用 dfs(pos+1,rest) 进行递归;

在某次递归开始前,如果 rest 的值为 0,说明我们找到了一个和为 target 的组合,将其放入答案中。每次调用递归函数前,如果我们选了那个数,就需要将其放入列表的末尾,该列表中存储了我们选的所有数。在回溯时,如果我们选了那个数,就要将其从列表的末尾删除。

上述算法就是一个标准的递归 + 回溯算法,但是它并不适用于本题。这是因为题目描述中规定了解集不能包含重复的组合,而上述的算法中并没有去除重复的组合。

例如当 candidates=[2,2],target=2 时,上述算法会将列表 [2] 放入答案两次。

因此,我们需要改进上述算法,在求出组合的过程中就进行去重的操作。我们可以考虑将相同的数放在一起进行处理,也就是说,如果数 x 出现了 y 次,那么在递归时一次性地处理它们,即分别调用选择 0,1,⋯,y 次 x 的递归函数。这样我们就不会得到重复的组合。具体地:

我们使用一个哈希映射(HashMap)统计数组 candidates 中每个数出现的次数。在统计完成之后,我们将结果放入一个列表 freq 中,方便后续的递归使用。

列表 freq 的长度即为数组 candidates 中不同数的个数。其中的每一项对应着哈希映射中的一个键值对,即某个数以及它出现的次数。
在递归时,对于当前的第 pos 个数,它的值为 freq[pos][0],出现的次数为 freq[pos][1],那么我们可以调用

dfs(pos+1,rest−i×freq[pos][0])

即我们选择了这个数 i 次。这里 i 不能大于这个数出现的次数,并且 i×freq[pos][0] 也不能大于 rest。同时,我们需要将 i 个 freq[pos][0] 放入列表中。

这样一来,我们就可以不重复地枚举所有的组合了。

我们还可以进行什么优化(剪枝)呢?一种比较常用的优化方法是,我们将 freq 根据数从小到大排序,这样我们在递归时会先选择小的数,再选择大的数。这样做的好处是,当我们递归到 dfs(pos,rest) 时,如果 freq[pos][0] 已经大于 rest,那么后面还没有递归到的数也都大于 rest,这就说明不可能再选择若干个和为 rest 的数放入列表了。此时,我们就可以直接回溯。

Python代码:

#
# 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
#
# 
# @param num int整型一维数组 
# @param target int整型 
# @return int整型二维数组
#
class Solution:
    def combinationSum2(self , num: List[int], target: int) -> List[List[int]]:
        # write code here
        def helper(index, remain):
            if remain == 0:
                res.append(ans[:])
                return None
            if remain < 0:
                return None
            for i in range(index, len(num)):
                if i > index and num[i] == num[i-1]:
                    continue
                ans.append(num[i])
                helper(i + 1, remain - num[i])
                ans.pop()
        num.sort()
        res = []
        ans = []
        helper(0, target)
        return res

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
LeetCode 是一个常用的编程学习和面试准备平台,而人工智能 (AI) 处理器组合指的是在处理 LeetCode 题目时,使用多个不同类型的 AI 处理器来提高算法性能和效率。 首先,AI 处理器是具有强大计算能力和优化算法的专用芯片。与传统的通用处理器相比,AI 处理器在处理大量数据和复杂计算任务时表现更佳。 AI 处理器组合意味着将不同类型的 AI 处理器结合使用,以便在编程和解决 LeetCode 题目时获得更好的性能。这些处理器可以包括图像处理单元 (GPU),张量处理单元 (TPU),以及专门针对特定AI应用开发的ASIC等。 在处理 LeetCode 题目时,AI 处理器组合可以带来多个好处。首先,AI 处理器具有并行计算能力,能够同时处理多个任务,从而算法的执行速度。其次,AI 处理器通过优化算法和模型,可以提高解题的准确性和效率。例如,对于一些图像和语音处理相关的题目,使用 GPU 或 TPU 可以速图像和声音的处理,从而更快地得到正确答案。 另外,AI 处理器组合还可以提供更多的资源和内存,以支持处理大规模数据和复杂问题。这对于一些需要使用深度学习或机器学习算法的题目非常重要,因为这些算法通常需要更多的计算资源和存储空间。 综上所述,AI 处理器组合对于处理 LeetCode 题目具有巨大的潜力。它可以算法的执行速度,提高解题的准确性和效率,并支持处理大规模数据和复杂问题。然而,组合不同类型的 AI 处理器需要适当的编程技巧和技术知识,以便充分发挥它们的优势和性能。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值