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

力扣经典算法篇-44-组合总和(回溯问题)

1、题干

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

2、解题

求所有组合的问题通常可以使用回溯算法就行求解。

回溯的基本实现步骤:
找到固定不变的量,每趟递归动态变化的量,结果集。
递归一定要有终止条件,终止条件要校验和添加结本趟结果到结果集合中。
循环递归,注意要先添加元素向前递归,之后进行回退操作;怎么添加的元素进行向后递归,就要怎么删除元素向前回溯。

方法一:(回溯法–结果校验处理)

利用回溯法的解答模版,可以获取所有可用排列的结果,但是可能造成重复问题。如:(2,2,3)和(2,3,2)实际上是想通过的结果。
所以保存结果时,需要校验是否重复,重复数据不能再次添加到结果集。

代码示例:

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;public class Test50 {public static List<List<Integer>> combinationSum(int[] candidates, int target) {// 不变的结果集List<List<Integer>> result = new ArrayList<>();// 每趟变量可变的元素// 每趟添加的元素List<Integer> tempList = new ArrayList<>();// 添加元素的下标int index = 0;// 当前趟的结果和int sum = 0;// 递归(不变的:目标数组candidates,目标值target; 每趟变化的:临时数组tempList,添加元素下标index,每一趟当前和sum; 结果集)goAndBack(candidates, target, tempList, index, sum, result);return result;}private static void goAndBack(int[] candidates, int target, List<Integer> tempList, int index, int sum, List<List<Integer>> result) {if (sum >= target) {// 大于等于目标值时,可以结束当前趟遍历if (sum == target) {// 当前趟元素排序后校验结果集是否存在,不存在可以添加到结果集ArrayList<Integer> oneGoal = new ArrayList<>(tempList);Collections.sort(oneGoal);if (!result.contains(oneGoal)){result.add(oneGoal);}}// 结果本趟递归,向前回溯return;}for (int i = 0; i < candidates.length; i++) {    // 因为元素可以重复添加,所以这里每次都从0号位置开始添加// 添加元素,计算和,向后递归tempList.add(candidates[i]);sum = sum + candidates[i];goAndBack(candidates, target, tempList, index + 1, sum + candidates[i], result);// 删除添加的元素,减去当前值,向前回溯sum = sum - candidates[i];tempList.remove(index);   // 或tempList.remove(tempList.size()-1); }}public static void main(String[] args) {int[] candidates = {2, 3, 6, 7};int target = 7;System.out.println(combinationSum(candidates, target));}
}

方法二:(回溯法–指定遍历的起始位置)

上面的方法一中,每次都是从位置0开始遍历添加元素,直到符合条件为止,相对而言,递归和回溯的次数都比较多。
可以换一种方式,在向后递归的时候,指定起始遍历的位置,即:下一次对的起始位置也是本次递归的起始位置,不是从0开始。这样就在遍历组装结果的过程中避免了重复的可能,减少遍历和比较的次数,效率更高。

代码示例:

 public List<List<Integer>> combinationSum(int[] candidates, int target) {List<List<Integer>> ans = new ArrayList<>();List<Integer> temp = new ArrayList<>();dfs(ans, temp, 0, 0, candidates, target);return ans;}public void dfs(List<List<Integer>> ans, List<Integer> temp, int index, int sum, int[] candidates, int target) {if (sum >= target) {if (sum == target) {ans.add(new ArrayList<>(temp));}return;}for (int i = index; i < candidates.length; i++) {// 添加元素,向后递归temp.add(candidates[i]);dfs(ans, temp, i, sum + candidates[i], candidates, target);     // 下一次遍历的位置i,最小也是index,避免过度回溯// 删除元素,向前回溯temp.remove(temp.size() - 1);}}

向阳前行,Dare To Be!!!

http://www.lryc.cn/news/611500.html

相关文章:

  • Ubuntu20.04 离线安装 FFmpeg 静态编译包
  • 【unity实战】用unity实现一个3D俯视角暗杀潜行恐怖类游戏,主要是实现视野范围可视化效果
  • X86-ubuntu22.04远程桌面只有1/4无法正常操作
  • 问题定位排查手记1 | 从Windows端快速检查连接状态
  • 分布式文件系统07-小文件系统的请求异步化高并发性能优化
  • ubuntu 22.04 中安装python3.11 和 3.11 的 pip
  • STM32U5 外部中断不响应问题分析
  • Ubuntu设置
  • DevOps时代的知识基座革命:Gitee Wiki如何重构研发协作范式
  • 基于51单片机的温控风扇Protues仿真设计
  • 【面试场景题】电商秒杀系统的库存管理设计实战
  • Python高级排序技术:非原生可比对象的自定义排序策略详解
  • 17.10 智谱AI GLM 篇:ChatGLM3-6B 快速上手
  • LeetCode每日一题,8-6
  • List、ArrayList 与顺序表
  • 软考软件设计师考点总结
  • 模电知识点总结
  • 安卓雷电模拟器安装frida调试
  • mysql优化策略
  • 【Excel】通过Index函数向下拖动单元格并【重复引用/循环引用】数据源
  • WinForm之ListView 组件
  • Ethereum: L1 与 L2 的安全纽带, Rollups 技术下的协作与区别全解析
  • Vue计算属性详解2
  • 无法解析 CentOS 官方镜像源的域名
  • 微软的BitLocker加密
  • 输电线路防外破声光预警装置 | 防山火/防钓鱼/防施工安全警示系统
  • 豆包新模型与PromptPilot工具深度测评:AI应用开发的全流程突破
  • UE编辑器相机窗口运行时相机fov 大小不一致
  • 嵌入式学习的第四十四天-ARM
  • 安装 cuda 版本 PyTorch(2025)