当前位置: 首页 > news >正文

【Leetcode hot 100】39.组合总和

问题链接

39.组合总和

问题描述

给你一个 无重复元素 的整数数组 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

问题解答

解题思路

  1. 核心原理:回溯算法本质是“暴力搜索+回溯撤销”,通过记录“当前路径”和“结果集”,逐步探索所有可能组合,不符合条件时撤销上一步选择(回溯)。
  2. 去重关键:为避免重复组合(如[2,2,3][2,3,2]),递归时从当前索引startIndex 开始遍历,而非从0开始,确保组合内元素按“非递减”顺序选取。
  3. 剪枝优化
    • 提前对candidates排序,当当前元素大于剩余target时,后续元素更大,直接break循环(无需继续遍历)。
    • 若当前路径和已超过target,直接终止递归(避免无效搜索)。

完整代码

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;class Solution {// 存储最终所有合法组合private List<List<Integer>> result = new ArrayList<>();// 存储当前正在构建的组合(路径)private List<Integer> path = new ArrayList<>();public List<List<Integer>> combinationSum(int[] candidates, int target) {// 排序:用于后续剪枝优化(关键步骤)Arrays.sort(candidates);// 调用回溯函数:从索引0开始探索,初始剩余target为传入值backtrack(candidates, target, 0);return result;}/*** 回溯函数* @param candidates 候选数组(已排序)* @param remainingTarget 剩余目标值(当前路径和与target的差值)* @param startIndex 当前遍历的起始索引(避免重复组合)*/private void backtrack(int[] candidates, int remainingTarget, int startIndex) {// 1. 终止条件:找到合法组合(剩余目标值为0)if (remainingTarget == 0) {// 注意:需new新列表,避免path引用被后续修改影响结果result.add(new ArrayList<>(path));return;}// 2. 遍历候选元素(从startIndex开始,避免重复)for (int i = startIndex; i < candidates.length; i++) {int currentNum = candidates[i];// 剪枝:当前元素大于剩余目标值,后续元素更大,直接终止循环if (currentNum > remainingTarget) {break;}// 3. 做选择:将当前元素加入路径,减少剩余目标值path.add(currentNum);// 4. 递归探索:下一层仍从i开始(允许重复选取当前元素)backtrack(candidates, remainingTarget - currentNum, i);// 5. 撤销选择(回溯):移除路径最后一个元素,恢复状态path.remove(path.size() - 1);}}
}

代码解析

  1. 成员变量
  • result:存储所有满足条件的组合(最终返回值)。
  • path:存储当前正在构建的组合(回溯过程中动态修改)。
  1. 主方法combinationSum
  • 排序:对candidates排序是剪枝的前提,确保后续遍历中元素递增,避免无效搜索。
  • 调用回溯:初始从索引0开始,剩余目标值为target
  1. 回溯方法backtrack
  • 终止条件:当remainingTarget == 0时,说明当前path的和等于target,将其加入result(需new新列表,因为path是引用类型,直接添加会被后续修改覆盖)。
  • 遍历逻辑:从startIndex开始遍历,确保组合不重复(若从0开始,会出现[2,3,2]这类重复组合)。
  • 剪枝操作:若currentNum > remainingTarget,由于数组已排序,后续元素更大,直接break循环,减少无效迭代。
  • 选择与撤销
    • 选择:path.add(currentNum),同时remainingTarget -= currentNum(缩小目标范围)。
    • 递归:传入i而非i+1,允许重复选取当前元素。
    • 撤销:path.remove(path.size() - 1),恢复path状态,进入下一轮循环探索其他可能。

测试示例验证

示例1:candidates = [2,3,6,7], target = 7

  1. 排序后:[2,3,6,7]
  2. 回溯过程:
    • 2开始:path=[2],剩余5→ 再选2path=[2,2],剩余3→ 再选2:剩余1(剪枝)→ 选3:剩余0,加入[2,2,3]
    • 3开始:path=[3],剩余4→ 选3:剩余1(剪枝)→ 选6(剪枝)。
    • 6开始:6>7(剪枝)。
    • 7开始:path=[7],剩余0,加入[7]
  3. 结果:[[2,2,3],[7]](符合预期)。

示例3:candidates = [2], target = 1

  • 排序后:[2]
  • 遍历:2>1(剪枝),无合法组合,返回[](符合预期)。

复杂度分析

  • 时间复杂度O(S)S为所有合法组合的长度之和(每个组合需遍历构建,剪枝后大幅减少无效搜索)。
  • 空间复杂度O(target),递归深度最坏为target/candidates[0](如candidates=[2], target=40,递归深度为20),path的最大长度也为递归深度。
http://www.dtcms.com/a/435685.html

相关文章:

  • 简述企业网站的建设过程成都建设局网站
  • 建设银行福州分行招聘网站做网站需要用到那些软件
  • 建网站发信息做推广wordpress做淘客网站
  • 【Stata手动安装ivreghdfe】
  • 网站建设厌倦福州网站制作案例
  • 局域网访问Win11下的WSL中的jupyter notebook
  • 自己做网站要学什么软件google浏览器入口
  • 网站建设硬件环境免费网站建站平台
  • 男女做那种的的视频网站洛可可设计公司logo
  • 零基础做地方门户网站c2c旅游电子商务平台
  • 社区微网站建设方案景安怎么把网站做别名
  • 常见的简单的网站制作邢台谷歌seo
  • 网站网站建设企业建设美丽中国征文大赛
  • I2C总线介绍
  • 哪里有网站app制作网站如何分页
  • 百度 站长工具研究院网站系统建设方案
  • 广东省省考备考(第一百一十二天10.2)——判断推理:加强题型(归纳总结)
  • 德州建设银行兑换网站网站建设价格标准报价单
  • day48-ECS实战3
  • LangChain-03-新型的Chain
  • 景区网站建设策划网站开发项目资金运用明细
  • 网站换了域名怎么查郑州网站开发公司
  • 常州微信网站建设信息英文网站注意事项
  • 模型轻量化三大核心技术之:量化与剪枝
  • 大型购物网站服务器经营性质的网站
  • 道滘镇网站建设如何衡量一个网站的价值
  • 【读书笔记】《C陷阱与缺陷》第8章:编程建议总结 | 写出更健壮的C代码
  • 成都网站关键词汉中网站建设公司
  • 做网站镜像做货源的网站
  • 成都网站建设新闻wordpress 图片不居中