LeetCode 题解工作台

组合总和

给你一个 无重复元素 的整数数组 candidates 和一个目标整数 target ,找出 candidates 中可以使数字和为目标数 target 的 所有 不同组合 ,并以列表形式返回。你可以按 任意顺序 返回这些组合。 candidates 中的 同一个 数字可以 无限制重复被选取 。如果…

category

2

题型

code_blocks

8

代码语言

hub

3

相关题

当前训练重点

中等 · 回溯·pruning

bolt

答案摘要

我们可以先对数组进行排序,方便剪枝。 接下来,我们设计一个函数 $dfs(i, s)$,表示从下标 开始搜索,且剩余目标值为 ,其中 和 都是非负整数,当前搜索路径为 ,答案为 。

Interview AiBox logo

Interview AiBox 实时 AI 助手,陪你讲清 回溯·pruning 题型思路

试试 AiBox 面试助手arrow_forward
description

题目描述

给你一个 无重复元素 的整数数组 candidates 和一个目标整数 target ,找出 candidates 中可以使数字和为目标数 target 的 所有 不同组合 ,并以列表形式返回。你可以按 任意顺序 返回这些组合。

candidates 中的 同一个 数字可以 无限制重复被选取 。如果至少一个数字的被选数量不同,则两种组合是不同的。 

对于给定的输入,保证和为 target 的不同组合数少于 150 个。

 

示例 1:

输入:candidates = [2,3,6,7], target = 7
输出:[[2,2,3],[7]]
解释:
2 和 3 可以形成一组候选,2 + 2 + 3 = 7 。注意 2 可以使用多次。
7 也是一个候选, 7 = 7 。
仅有这两种组合。

示例 2:

输入: candidates = [2,3,5], target = 8
输出: [[2,2,2,2],[2,3,3],[3,5]]

示例 3:

输入: candidates = [2], target = 1
输出: []

 

提示:

  • 1 <= candidates.length <= 30
  • 2 <= candidates[i] <= 40
  • candidates 的所有元素 互不相同
  • 1 <= target <= 40
lightbulb

解题思路

方法一:排序 + 剪枝 + 回溯

我们可以先对数组进行排序,方便剪枝。

接下来,我们设计一个函数 dfs(i,s)dfs(i, s),表示从下标 ii 开始搜索,且剩余目标值为 ss,其中 iiss 都是非负整数,当前搜索路径为 tt,答案为 ansans

在函数 dfs(i,s)dfs(i, s) 中,我们先判断 ss 是否为 00,如果是,则将当前搜索路径 tt 加入答案 ansans 中,然后返回。如果 s<candidates[i]s \lt candidates[i],说明当前下标及后面的下标的元素都大于剩余目标值 ss,路径不合法,直接返回。否则,我们从下标 ii 开始搜索,搜索的下标范围是 j[i,n)j \in [i, n),其中 nn 为数组 candidatescandidates 的长度。在搜索的过程中,我们将当前下标的元素加入搜索路径 tt,递归调用函数 dfs(j,scandidates[j])dfs(j, s - candidates[j]),递归结束后,将当前下标的元素从搜索路径 tt 中移除。

在主函数中,我们只要调用函数 dfs(0,target)dfs(0, target),即可得到答案。

时间复杂度 O(2n×n)O(2^n \times n),空间复杂度 O(n)O(n)。其中 nn 为数组 candidatescandidates 的长度。由于剪枝,实际的时间复杂度要远小于 O(2n×n)O(2^n \times n)

相似题目:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
class Solution:
    def combinationSum(self, candidates: List[int], target: int) -> List[List[int]]:
        def dfs(i: int, s: int):
            if s == 0:
                ans.append(t[:])
                return
            if s < candidates[i]:
                return
            for j in range(i, len(candidates)):
                t.append(candidates[j])
                dfs(j, s - candidates[j])
                t.pop()

        candidates.sort()
        t = []
        ans = []
        dfs(0, target)
        return ans
speed

复杂度分析

指标
时间complexity depends on the number of valid combinations and recursion depth, which is influenced by the target value and candidate magnitudes. Space complexity is driven by recursion stack depth and storage of all valid combinations.
空间Depends on the final approach
psychology

面试官常问的追问

外企场景
  • question_mark

    Checks if you handle repeated use of candidates correctly.

  • question_mark

    Observes whether you prune branches when the cumulative sum exceeds the target.

  • question_mark

    Evaluates if you maintain the uniqueness of combinations without extra structures.

warning

常见陷阱

外企场景
  • error

    Failing to prune when the path sum exceeds the target, causing unnecessary recursion.

  • error

    Modifying the path in place without restoring it, leading to incorrect combinations.

  • error

    Incrementing the index too early and missing valid repeated candidate combinations.

swap_horiz

进阶变体

外企场景
  • arrow_right_alt

    Limit each candidate to be used at most once, changing the backtracking logic to increment the index after use.

  • arrow_right_alt

    Return combinations in non-descending order and remove duplicates, requiring sorting and skipping duplicates.

  • arrow_right_alt

    Find combinations whose sum is closest to a target without exceeding it, needing additional tracking of best sums.

help

常见问题

外企场景

组合总和题解:回溯·pruning | LeetCode #39 中等