青训营AI刷题 回溯 二叉树 组合总和问题 | 豆包MarsCode AI刷题

62 阅读3分钟

题目重述

给定一个无重复元素的正整数数组 candidates 和一个正整数 target,需要找出 candidates 中所有可以使数字和为目标数 target 的唯一组合。candidates 中的数字可以无限制重复被选取。如果至少一个所选数字数量不同,则两种组合是不同的。

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

示例

示例 1:

  • 输入: candidates = [2,3,6,7], target = 7
  • 输出: [[7],[2,2,3]]

示例 2:

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

示例 3:

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

示例 4:

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

示例 5:

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

问题分析

本题需要从给定的无重复元素正整数数组 “candidates” 里,挖掘出所有数字之和等于正整数 “target” 的独特组合,同时数组内数字可无限制重复选用。这是一道典型的组合搜索类问题,核心解题思路聚焦于 “搜索回溯” 策略,比较容易想到且易于实现的方法就是构造二叉树,并且用递归的方式进行遍历。

关键在于定义递归函数 dfs (target,combine,idx),按照深度优先搜索遍历可能的结果。同时我们初步分析一下终止条件设定,一旦 target 值小于等于 0,意味着组合已达或超出目标和,无需继续;或者 idx 超出数组边界、数组被 “用尽”,搜索便走到尽头。在递归步骤中,既可选跳过 idx 位数字,调用 dfs (target,combine,idx + 1),探索后续新元素组合可能;也能取用 idx 位数字,借 dfs (target - candidates [idx],combine,idx) 多次复用当前字符。树形展开、层层递进又按需回溯的机制,可以罗列所有可行解。

参考核心代码

all_res = []
def dfs(combine,target,idx,candidates):

    if target == 0:
        all_res.append(combine)
        return
    if target<0 or idx>=len(candidates):
        return
        
    dfs(combine+[candidates[idx]],target-candidates[idx],idx,candidates)
    dfs(combine,target,idx+1,candidates)


def combinationSum(candidates, target):
    if target<=0 or len(candidates) == 0:
        return []
    idx = 0
    dfs([candidates[0]],target-candidates[0],idx,candidates)
    dfs([],target,idx+1,candidates)
    return all_res

代码分析

首先考虑特殊情况,即当需要搜索的目标值是0,或者可候选的成员数长度为0时,不存在任何组合,直接返回空列表。否则,由入口程序执行dfs递归的第一步。

该逻辑是将所有的数值分为两种操作可能(构造二叉树),即选择当前数值和不选择当前数值(指针移动到下一个数值)。其中,idx 定位在 “candidates” 数组当下所考察的位置索引,target 量化剩余待组合达成的数值额度,combine 则忠实记录已挑选组合的数字列表。如果数值被选中,则target-被选中的数值 后传递到下一级dfs,再由下一级dfs决定是否继续选择当前数值。

当target = 0时,遍历的元素刚好能凑成target,否则小于零则代表凑过头了,也有可能是根据搜索策略已经没有可供选择的候选数值了,则代表此路不通,搜索结束。

最后将每一条路线的combine值记录在all_res中 按数组输出即可。