回溯算法-组合问题

回溯算法-组合问题

77. 组合

问题描述

给定两个整数 nk,返回范围 [1, n] 中所有可能的 k 个数的组合。

你可以按 任何顺序 返回答案。

示例 1:

输入:n = 4, k = 2
输出:
[[2,4],[3,4],[2,3],[1,2],[1,3],[1,4],
]

示例 2:

输入:n = 1, k = 1
输出:[[1]]

提示:

  • 1 <= n <= 20
  • 1 <= k <= n

解题思路与代码实现

class Solution {private List<List<Integer>> res = new ArrayList<>();    // 保存最终结果private LinkedList<Integer> path = new LinkedList<>();    // 暂存某一条解空间树中的路径public List<List<Integer>> combine(int n, int k) {backtracking(n, k, 1);    // 递归return res;}/*** 递归,纵向探索解空间树** @param start 起始位置*/private void backtracking(int n, int k, int start) {// path已存了k个元素,停止递归并合并结果if (path.size() == k) {// 使用深拷贝res.add(new ArrayList<>(path));return;}// for循环:横向枚举该层的所有可能,// 剪枝:例当n=4,k=3时,目前已经选取的元素为0(path.size为0),n - (k - 0) + 1 即 4 - ( 3 - 0) + 1 = 2for (int i = start; i <= n - (k - path.size()) + 1; i++) {path.addLast(i);backtracking(n, k, i+1);    // 递归path.removeLast(); // 回溯,撤销处理结果}}
}

踩坑点

如何进行剪枝优化

17. 电话号码的字母组合

问题描述

给定两个整数 nk,返回范围 [1, n] 中所有可能的 k 个数的组合。

你可以按 任何顺序 返回答案。

给定一个仅包含数字 2-9 的字符串,返回所有它能表示的字母组合。答案可以按 任意顺序 返回。

给出数字到字母的映射如下(与电话按键相同)。注意 1 不对应任何字母。

img

示例 1:

输入:digits = "23"
输出:["ad","ae","af","bd","be","bf","cd","ce","cf"]

示例 2:

输入:digits = ""
输出:[]

示例 3:

输入:digits = "2"
输出:["a","b","c"]

提示:

  • 0 <= digits.length <= 4
  • digits[i] 是范围 ['2', '9'] 的一个数字。

示例 1:

输入:n = 4, k = 2
输出:
[[2,4],[3,4],[2,3],[1,2],[1,3],[1,4],
]

示例 2:

输入:n = 1, k = 1
输出:[[1]]

提示:

  • 1 <= n <= 20
  • 1 <= k <= n

解题思路与代码实现

class Solution {private static Map<String, String[]> map = new HashMap<>(); // 存储数字和字母的映射private List<String> res = new ArrayList<>();   // 保存最终结果static {// 初始化数字和字母的映射map.put("2", new String[]{"a", "b", "c"});map.put("3", new String[]{"d", "e", "f"});map.put("4", new String[]{"g", "h", "i"});map.put("5", new String[]{"j", "k", "l"});map.put("6", new String[]{"m", "n", "o"});map.put("7", new String[]{"p", "q", "r", "s"});map.put("8", new String[]{"t", "u", "v"});map.put("9", new String[]{"w", "x", "y", "z"});}public List<String> letterCombinations(String digits) {if (!digits.isEmpty()) {    // 字符串判空backtracking(digits, 0, new StringBuilder());}return res;}/*** 回溯函数* @param digits 数字字符串* @param index 当前层数字对应数字字符串中的下标* @param builder 动态字符串*/private void backtracking(String digits, int index, StringBuilder builder) {if (builder.toString().length() == digits.length()) {   // 收集到digits.length()个字母// 合并结果res.add(builder.toString());return;}// 获取当成层对应的字母String[] letters = map.get(digits.charAt(index) + "");for (int i = 0; i < letters.length; i++) {builder.append(letters[i]); // 末尾拼接新的字母backtracking(digits, index + 1, builder);   // 递归builder.deleteCharAt(builder.length() - 1); // 移除末尾拼接的字母}}
}

踩坑点

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

解题思路与代码实现

class Solution {private List<List<Integer>> res = new ArrayList<>();    // 保存最终结果private LinkedList<Integer> path = new LinkedList<>();    // 暂存某一条解空间树中的路径private int currentSum = 0; // path中的元素和public List<List<Integer>> combinationSum(int[] candidates, int target) {Arrays.sort(candidates);    // 升序排序backtracking(candidates, target, 0);return res;}/*** 回溯函数* 本题区别于组合总和,每层的节点都有n个分叉(n为candidates候选数组的长度)** @param start 起始下标*/private void backtracking(int[] candidates, int target, int start) {if (target == currentSum) {   // 收集到和为target的一组数// 合并结果(深拷贝)res.add(new ArrayList<>(path));return;}// 当前每层的节点都有n个分叉,代表candidates数组各个元素// 剪枝:如果 currentSum + candidates[i] > target 就终止遍历for (int i = start; i < candidates.length && currentSum + candidates[i] <= target; i++) {path.addLast(candidates[i]);currentSum += candidates[i];// 递归,起始下标为i有去重的效果,如样例1,计算出2,2,2后,不算重复计算3,2,2backtracking(candidates, target, i);currentSum -= candidates[i];    // 回溯path.removeLast();  // 回溯}}
}

踩坑点

需要设置变量记录当前path列表中的元素和

40. 组合总和 II

问题描述

给定一个候选人编号的集合 candidates 和一个目标数 target ,找出 candidates 中所有可以使数字和为 target 的组合。

candidates 中的每个数字在每个组合中只能使用 一次

**注意:**解集不能包含重复的组合。

示例 1:

输入: candidates = [10,1,2,7,6,1,5], target = 8,
输出:
[
[1,1,6],
[1,2,5],
[1,7],
[2,6]
]

示例 2:

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

提示:

  • 1 <= candidates.length <= 100
  • 1 <= candidates[i] <= 50
  • 1 <= target <= 30

解题思路与代码实现

class Solution {private List<List<Integer>> res = new ArrayList<>();    // 保存最终结果private LinkedList<Integer> path = new LinkedList<>();    // 暂存某一条解空间树中的路径private int currentSum = 0; // path中的元素和public List<List<Integer>> combinationSum2(int[] candidates, int target) {Arrays.sort(candidates);    // 升序排序backtracking(candidates, target, 0);return res;}/*** 回溯函数* 这道题目和39.组合总和 (opens new window)如下区别:* 1.本题candidates 中的每个数字在每个组合中只能使用一次。* 2.本题数组candidates的元素是有重复的,而39.组合总和 (opens new window)是无重复元素的数组candidates* 踩坑:解空间树层去重:如用例candidates = [1,1,2,4],target = 5,当i=0时,有[1,4],当i=1时,无需在重复计算,跳过本轮循环(剪枝)* @param start 起始下标*/private void backtracking(int[] candidates, int target, int start) {// currentSum>target不会执行if和for循环if (target == currentSum) {   // 收集到和为target的一组数// 合并结果(深拷贝)res.add(new ArrayList<>(path));return;}// 剪枝:如果 currentSum + candidates[i] > target 就终止遍历for (int i = start; i < candidates.length && currentSum + candidates[i] <= target; i++) {// 特别测试用例:1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1 没有这一步可能会超时// 如果有相邻的重复元素,如candidates[i]== candidates[i - 1],candidates[i-1]试过了则andidates[i]不需要重复计算,需要剪枝if (i > start && candidates[i] == candidates[i - 1]) {continue;}path.addLast(candidates[i]);currentSum += candidates[i];// 递归,起始下标为i有去重的效果,避免重复计算backtracking(candidates, target, i + 1);currentSum -= candidates[i];    // 回溯path.removeLast();  // 回溯}}
}

踩坑点

重复元素需要避免重复计算,否则会超时

216. 组合总和 III

问题描述

找出所有相加之和为 nk 个数的组合,且满足下列条件:

  • 只使用数字1到9
  • 每个数字 最多使用一次

返回 所有可能的有效组合的列表 。该列表不能包含相同的组合两次,组合可以以任何顺序返回。

示例 1:

输入: k = 3, n = 7
输出: [[1,2,4]]
解释:
1 + 2 + 4 = 7
没有其他符合的组合了。

示例 2:

输入: k = 3, n = 9
输出: [[1,2,6], [1,3,5], [2,3,4]]
解释:
1 + 2 + 6 = 9
1 + 3 + 5 = 9
2 + 3 + 4 = 9
没有其他符合的组合了。

示例 3:

输入: k = 4, n = 1
输出: []
解释: 不存在有效的组合。
在[1,9]范围内使用4个不同的数字,我们可以得到的最小和是1+2+3+4 = 10,因为10 > 1,没有有效的组合。

提示:

  • 2 <= k <= 9
  • 1 <= n <= 60

解题思路与代码实现

class Solution {private Integer currentSum = 0;    // 暂存path的元素和private List<List<Integer>> res = new ArrayList<>();    // 保存最终结果private LinkedList<Integer> path = new LinkedList<>();    // 暂存某一条解空间树中的路径/*** 找出所有相加之和为 n 的 k 个数的组合,且满足下列条件:* 只使用数字1到9* 每个数字 最多使用一次*/public List<List<Integer>> combinationSum3(int k, int n) {backtracking(n, k, 1);return res;}/*** 递归,纵向探索解空间树** @param start 起始位置*/private void backtracking(int n, int k, int start) {// path已存了k个元素,停止递归并合并结果if (path.size() == k ) {if (currentSum == n){   // 和为n的才保存到结果中// 使用深拷贝res.add(new ArrayList<>(path));}return;}// for循环:横向枚举该层的所有可能,for (int i = start; i <= 9 && currentSum + i <= n; i++) {path.addLast(i);currentSum += i;backtracking(n, k, i + 1);    // 递归currentSum -= i;path.removeLast(); // 回溯,撤销处理结果}}
}

踩坑点

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/1483.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

05集合-CollectionListSet

Collection体系的特点、使用场景总结 如果希望元素可以重复&#xff0c;又有索引&#xff0c;索引查询要快? 用ArrayList集合, 基于数组的。(用的最多) 如果希望元素可以重复&#xff0c;又有索引&#xff0c;增删首尾操作快? 用LinkedList集合, 基于链表的。 如果希望增…

基于SpringBoot + Vue实现的奖学金管理系统设计与实现+毕业论文+答辩PPT

介绍 角色:管理员、学院负责人、学校负责人、学生 管理员:管理员登录进入高校奖助学金系统的实现可以查看系统首页、个人中心、学生管理、学院负责人管理、学校负责人管理、奖学金类型管理、奖学金申请管理、申请提交管理、系统管理等信息 学院负责人:学院负责人登录系统后&am…

python3--lxml pytoml.core.TomlError expected_equals报错解决

文章目录 一、问题二. 解决方法&#xff1a;三. 参考&#xff1a;四. 总结 一、问题 在ubuntu的armbian上的python3中安装lxml时报错了 安装命令是 pip3 install lxml报错简略信息如下图 File "/usr/share/python-wheels/pytoml-0.1.2-py2.py3-none-any.whl/pytoml/par…

2.1K Star微软开源的高质量 iot库

功能描述 该项目是一个开源的 .NET Core 实现&#xff0c;旨在帮助开发者构建适用于物联网(IoT)设备和场景的应用程序。它提供了与传感器、显示器和输入设备等相互作用所需的 GPIO 引脚、串口等硬件的接口。该仓库包含 System.Device.Gpio 库以及针对各种板卡&#xff08;如 Ra…

redis底层数据结构之ziplist

目录 一、概述二、ziplist结构三、Entry结构四、为什么ZipList特别省内存五、ziplist的缺点 上一篇 redis底层数据结构之SDS 下一篇 明天更新 一、概述 一种连续内存空间存储的顺序数据结构&#xff0c;每个元素可以是字符串或整数。优点:节省内存空间。适用于存储小规模的列表…

STM32 | USART实战案例

STM32 | 通用同步/异步串行接收/发送器USART带蓝牙(第六天)随着扩展的内容越来越多,很多小伙伴已经忘记了之前的学习内容,然后后面这些都很难理解。STM32合集已在专栏创建,方面大家学习。1、通过电脑串口助手发送数据,控制开发板LED灯 从题目中可以挖掘出,本次使用led、延…

【Linux文件系统开发】认知篇

【Linux文件系统开发】认知篇 文章目录 【Linux文件系统开发】认知篇一、文件系统的概念二、文件系统的种类&#xff08;文件管理系统的方法&#xff09;三、分区四、文件系统目录结构五、虚拟文件系统&#xff08;Virtual File System&#xff09;1.概念2.原因3.作用4.总结 一…

减肥变成一种趋势!足球直播是一种刺激——早读(逆天打工人爬取热门微信文章解读)

看直播是打发时间的好方式 引言Python 代码第一篇 洞见 跌入粪坑的钟美美&#xff0c;才是真正的“人间清醒”第二篇 人民日报 来了&#xff01;新闻早班车要闻社会政策 结尾 变化是生活的法则 而直播的比赛则是这一法则的缩影 每一秒都可能带来转折和惊喜 充满了未知和奇迹 引…

磁盘损坏无法读取:原因、恢复方案与防范之道

在数字化信息爆炸的时代&#xff0c;磁盘作为数据存储的重要载体&#xff0c;承载着无数重要的文件和资料。然而&#xff0c;当磁盘突然损坏&#xff0c;无法读取数据时&#xff0c;我们往往会陷入困境&#xff0c;焦虑不已。面对这种情况&#xff0c;我们该如何应对&#xff1…

Yolo-world使用

1、安装 python pip install ultralytics 前往官网下载模型&#xff1a;https://docs.ultralytics.com/models/yolo-world/#key-features 我这里使用yolov8s-world.pt举例 最简单的使用示例 if __name__ __main__:model YOLO(model/yolov8s-world.pt)results model.pre…

中仕公考:考公还是考编?区别是什么?

公务员和事业编应该如何选择?区别在哪里?中仕为大家总结以下几点&#xff0c;看完就明白了! 事业编制&#xff1a;主要指从事事业单位工作人员所获得的稳定的事业单位编制。 公务员&#xff1a;是指在各级政府机关中&#xff0c;行使国家行政职权&#xff0c;执行国家公务的…

2024HW ---->内网横向移动

在蓝队的面试过程中&#xff0c;如果你会内网渗透的话&#xff0c;那是肯定的一个加分选项&#xff01;&#xff01;&#xff01; 那么从今天开始&#xff0c;我们就来讲一下内网的横向移动&#xff01;&#xff01;&#xff01; 目录 1.域内任意用户枚举 2.Password-Sprayi…

ffmpeg入门

ffmpeg入——安装 Fmpeg地址 FFmpeg源码地址&#xff1a;GitHub - FFmpeg/FFmpeg: Mirror of https://git.ffmpeg.org/ffmpeg.git FFmpeg可执行文件地址&#xff1a;Download FFmpeg Windows平台 ​ ​ Windows平台下载解压后如图所示&#xff08;文件名称以-share结尾的…

深入剖析Spring框架:循环依赖的解决机制

你好&#xff0c;我是柳岸花开。 什么是循环依赖&#xff1f; 很简单&#xff0c;就是A对象依赖了B对象&#xff0c;B对象依赖了A对象。 在Spring中&#xff0c;一个对象并不是简单new出来了&#xff0c;而是会经过一系列的Bean的生命周期&#xff0c;就是因为Bean的生命周期所…

如何添加所有未跟踪文件到暂存区?

文章目录 如何将所有未跟踪文件添加到Git暂存区&#xff1f;步骤与示例代码1. 打开命令行或终端2. 列出所有未跟踪的文件3. 添加所有未跟踪文件到暂存区4. 验证暂存区状态 如何将所有未跟踪文件添加到Git暂存区&#xff1f; 在版本控制系统Git中&#xff0c;当我们首次创建新文…

安全狗云眼的主要功能有哪些?

"安全狗云眼"是一款综合性的网络安全产品&#xff0c;主要用于实时监控和保护企业的网络安全。其核心功能包括威胁检测、漏洞扫描、日志管理和合规性检查等。 以下是安全狗云眼的主要功能详细介绍&#xff1a; 1、资产管理 定期获取并记录主机上的Web站点、Web容器、…

【科大讯飞笔试题汇总】2024-04-21-科大讯飞春招笔试题-三语言题解(CPP/Python/Java)

&#x1f36d; 大家好这里是KK爱Coding &#xff0c;一枚热爱算法的程序员 ✨ 本系列打算持续跟新科大讯飞近期的春秋招笔试题汇总&#xff5e; &#x1f4bb; ACM银牌&#x1f948;| 多次AK大厂笔试 &#xff5c; 编程一对一辅导 &#x1f44f; 感谢大家的订阅➕ 和 喜欢&…

卷积神经网络 (CNN)

计算机视觉最常见的机器学习模型体系结构之一是卷积神经网络 (CNN)。 CNN 使用筛选器从图像中提取数值特征图&#xff0c;然后将特征值馈送到深度学习模型中以生成标签预测。 例如&#xff0c;在图像分类方案中&#xff0c;标签表示图像的主要主题&#xff08;换句话说&#xf…

微信有关白名单IP

一、商家支付 二、公众号

开启智慧之旅,AI与机器学习驱动的微服务设计模式探索

​&#x1f308; 个人主页&#xff1a;danci_ &#x1f525; 系列专栏&#xff1a;《设计模式》 &#x1f4aa;&#x1f3fb; 制定明确可量化的目标&#xff0c;坚持默默的做事。 &#x1f680; 转载自热榜文章&#x1f525;&#xff1a;探索设计模式的魅力&#xff1a;开启智慧…