代码随想录-Day25

216.组合总和III

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

只使用数字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
没有其他符合的组合了。

方法一:二进制(子集)枚举

class Solution {List<Integer> temp = new ArrayList<Integer>();List<List<Integer>> ans = new ArrayList<List<Integer>>();public List<List<Integer>> combinationSum3(int k, int n) {for (int mask = 0; mask < (1 << 9); ++mask) {if (check(mask, k, n)) {ans.add(new ArrayList<Integer>(temp));}}return ans;}public boolean check(int mask, int k, int n) {temp.clear();for (int i = 0; i < 9; ++i) {if (((1 << i) & mask) != 0) {temp.add(i + 1);}}if (temp.size() != k) {return false;}int sum = 0;for (int num : temp) {sum += num;}return sum == n;}
}

这段代码也是定义了一个名为 Solution 的类,但这次是解决一个略有不同的组合问题——找出所有和为 n 且正好由 k 个数字组成的序列,这些数字取自 1 到 9 之间的整数,每个数字最多使用一次。这是一种使用位操作优化的组合求解方法。

成员变量

与之前一样,定义了两个成员变量:

  • temp:一个 List<Integer>,用于临时存储当前组合。
  • ans:一个 List<List<Integer>>,用于存储所有满足条件的组合。

方法

combinationSum3(int k, int n)
  • 功能:主方法,接收目标和 n 和组合长度 k 作为参数,返回所有符合条件的组合。
  • 过程:通过遍历从 0(1 << 9)(即 2^9)之间所有可能的掩码值(mask),利用 check 方法验证每个掩码是否代表一个有效的组合。如果是,则将该组合添加到答案列表 ans 中。
check(int mask, int k, int n)
  • 功能:辅助方法,检查给定的掩码 mask 是否代表一个有效的组合,即组合中的数字个数是否为 k 且这些数字之和为 n
  • 参数:除了掩码 mask 外,还接收组合长度 k 和目标和 n
  • 过程
    • 首先清空 temp,然后遍历从 0 到 8(代表数字 1 到 9),如果某位在 mask 中被设置(即该位为 1),则将对应的数字(i + 1)添加到 temp 中。
    • 检查 temp 的大小是否等于 k,如果不等直接返回 false
    • 计算 temp 中所有数字的和,判断这个和是否等于 n,如果相等返回 true,否则返回 false

这种方法利用位运算高效地枚举了所有可能的选择情况,相比于之前的递归解法,此方法在某些情况下可以减少递归调用的开销,尤其是在处理较大范围的组合问题时更为高效。

方法二:组合枚举

class Solution {List<Integer> temp = new ArrayList<Integer>();List<List<Integer>> ans = new ArrayList<List<Integer>>();public List<List<Integer>> combinationSum3(int k, int n) {dfs(1, 9, k, n);return ans;}public void dfs(int cur, int n, int k, int sum) {if (temp.size() + (n - cur + 1) < k || temp.size() > k) {return;}if (temp.size() == k) {int tempSum = 0;for (int num : temp) {tempSum += num;}if (tempSum == sum) {ans.add(new ArrayList<Integer>(temp));return;}}temp.add(cur);dfs(cur + 1, n, k, sum);temp.remove(temp.size() - 1);dfs(cur + 1, n, k, sum);}
}

这段代码是用Java编写的,它定义了一个名为Solution的类,该类包含方法来找出所有组合之和等于特定目标值n的k个不同正整数的组合,且这些整数都在1到n之间(这里限制为1到9,因为题目隐含了这个范围,如dfs函数的第二个参数所示)。这是一个经典的回溯算法应用实例。

方法说明

  • combinationSum3(int k, int n): 这是主要的方法,接收两个整数参数kn,分别代表需要找到的组合的元素个数以及这些元素的和。它初始化调用深度优先搜索(dfs)方法来寻找所有符合条件的组合,并返回存储这些组合的二维列表ans

  • dfs(int cur, int n, int k, int sum): 这是一个递归辅助函数,用于执行深度优先搜索。

    • cur表示当前考虑加入组合的起始数字(递增的基础)。
    • n是可选数字的最大值,在这个上下文中固定为9。
    • ksum与主方法接收的参数相同,分别代表需要的组合长度和目标和。

    该函数的工作原理如下:

    • 剪枝:首先判断当前路径是否有可能达到解。如果当前临时组合的长度加上剩余数字的数量小于k,或者已经超过k,直接返回,无需继续搜索。
    • 结束条件:当临时组合的长度等于k时,检查这些数字的和是否等于目标sum。如果是,则将当前组合添加到答案列表中,并返回。
    • 递归搜索:尝试选择当前数字cur,将其加入临时组合temp,然后递归调用dfs函数尝试下一个数字。之后通过temp.remove(temp.size() - 1)撤销选择(回溯),再尝试不包含当前数字的情况。

示例解析

假设调用combinationSum3(3, 7),该函数将寻找所有和为7且包含3个数字的组合,这些数字来自1到9。可能的结果包括[1, 2, 4]。此过程通过深度优先搜索逐层尝试每一种可能的组合,并通过剪枝策略减少无效的搜索路径,从而高效地找到所有解。

方法三:回溯


// 上面剪枝 i <= 9 - (k - path.size()) + 1; 如果还是不清楚
// 也可以改为 if (path.size() > k) return; 执行效率上是一样的
class Solution {LinkedList<Integer> path = new LinkedList<>();List<List<Integer>> ans = new ArrayList<>();public List<List<Integer>> combinationSum3(int k, int n) {build(k, n, 1, 0);return ans;}private void build(int k, int n, int startIndex, int sum) {if (sum > n) return;if (path.size() > k) return;if (sum == n && path.size() == k) {ans.add(new ArrayList<>(path));return;}for(int i = startIndex; i <= 9; i++) {path.add(i);sum += i;build(k, n, i + 1, sum);sum -= i;path.removeLast();}}
}

这段代码同样定义了一个名为 Solution 的类,用于解决找出所有和为 n 且包含恰好 k 个不同数字的组合的问题,其中数字选择范围限定在 1 到 9 之间。与之前版本相比,这段代码采用了一些小的改动和优化,使用了 LinkedList 作为路径的存储结构,以更直观地展示组合构建过程,并在剪枝策略上做了调整。下面是详细的解析:

类成员变量

  • LinkedList<Integer> path:用于保存当前搜索路径上的数字组合。
  • List<List<Integer>> ans:用于存储所有满足条件的组合。

主方法 combinationSum3(int k, int n)

  • 功能:接收目标和 n 和组合长度 k 作为参数,调用 build 方法生成所有符合条件的组合,最后返回所有组合的列表 ans

辅助方法 build(int k, int n, int startIndex, int sum)

  • 功能:递归构建组合。接收当前需要的组合长度 k、目标和 n、搜索起始数字 startIndex 以及当前路径和 sum 作为参数。
  • 剪枝条件
    • 如果 sum > n,说明当前路径的和已经超过了目标和,直接返回。
    • 如果 path.size() > k,说明已经选择了超过 k 个数字,违反了组合长度的限制,同样直接返回。
  • 终止条件:当当前路径的和等于 n 且已选择的数字个数等于 k 时,将当前路径添加到结果列表 ans 中。
  • 递归构建:从 startIndex 开始遍历至 9,将当前数字 i 加入路径,然后递归调用 build 方法进行下一层搜索,之后通过 path.removeLast() 回溯,移除刚刚加入的数字,尝试下一个数字。

剪枝策略说明

原注释中提到的剪枝条件 i <= 9 - (k - path.size()) + 1; 与代码中采用的剪枝条件 if (path.size() > k) return; 实现了相同的功能,但后者更直观易懂。它确保了在任何时候路径中的数字数量都不会超过所需组合的长度 k,从而避免了无效的搜索,保证了算法效率。两种剪枝策略在执行效率上基本一致,但后者在代码可读性上更优。

17. 电话号码的字母组合

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

给出数字到字母的映射如下(与电话按键相同)。注意 1 不对应任何字母。
在这里插入图片描述

方法一:回溯

class Solution {public List<String> letterCombinations(String digits) {List<String> combinations = new ArrayList<String>();if (digits.length() == 0) {return combinations;}Map<Character, String> phoneMap = new HashMap<Character, String>() {{put('2', "abc");put('3', "def");put('4', "ghi");put('5', "jkl");put('6', "mno");put('7', "pqrs");put('8', "tuv");put('9', "wxyz");}};backtrack(combinations, phoneMap, digits, 0, new StringBuffer());return combinations;}public void backtrack(List<String> combinations, Map<Character, String> phoneMap, String digits, int index, StringBuffer combination) {if (index == digits.length()) {combinations.add(combination.toString());} else {char digit = digits.charAt(index);String letters = phoneMap.get(digit);int lettersCount = letters.length();for (int i = 0; i < lettersCount; i++) {combination.append(letters.charAt(i));backtrack(combinations, phoneMap, digits, index + 1, combination);combination.deleteCharAt(index);}}}
}

这段代码是一个 Java 程序,实现了一个名为 Solution 的类,该类包含两个方法:letterCombinationsbacktrack。这个程序的目的是根据给定的电话号码数字字符串(比如 “23”)生成所有可能的字母组合(“ad”, “ae”, “af”, “bd”, “be”, “bf”, “cd”, “ce”, “cf”)。这里,每个数字映射到多个字母(比如 ‘2’ 映射到 “abc”),这些映射关系已经预定义在 phoneMap 中。

方法说明

  1. letterCombinations(String digits)

    • 功能:这是主要的接口方法,接收一个字符串 digits 作为输入,返回一个包含所有可能字母组合的列表。
    • 逻辑:首先检查输入字符串是否为空,若为空则直接返回一个空列表。接着,定义了一个哈希映射 phoneMap,将数字字符映射到对应的字母字符串。然后,调用 backtrack 方法进行回溯操作生成所有组合,并将结果收集到 combinations 列表中。
  2. backtrack(List combinations, Map<Character, String> phoneMap, String digits, int index, StringBuffer combination)

    • 功能:递归回溯方法,用于生成所有可能的字母组合。
    • 参数
      • combinations: 存储所有组合的列表。
      • phoneMap: 数字到字母的映射。
      • digits: 输入的数字字符串。
      • index: 当前处理的 digits 中字符的索引。
      • combination: 当前正在构建的组合的缓冲区。
    • 逻辑
      • 基准情况:如果 index 等于 digits 的长度,说明已经完成一个组合,将其添加到 combinations 列表中。
      • 递归情况:根据当前 index 所对应的数字从 phoneMap 获取对应字母串,遍历这个字母串中的每个字母,将其添加到 combination 中,然后递归调用自身处理下一个数字。在递归返回后,通过 deleteCharAt 方法回溯,移除刚添加的字母,尝试下一个字母。

示例解析

例如,当输入 “23” 时,首先映射 ‘2’ 到 “abc”,然后 ‘3’ 到 “def”。程序会从 “2” 开始,对 “abc” 中的每个字母与 “def” 中的每个字母进行组合,最终生成所有可能的字母组合并返回。

这种方法利用回溯算法有效地减少了重复计算,保证了所有组合都被遍历且只被生成一次,适合解决此类组合问题。

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

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

相关文章

Python OCR 图片转文字进阶:读光OCR之行检测模型+行识别模型

Python OCR 图片转文字进阶&#xff1a;读光OCR之行检测模型行识别模型 介绍阿里云文字识别OCR&#xff08;读光OCR&#xff09;前置条件模型1&#xff1a;行检测模型模型1&#xff1a;行识别模型 代码&#xff1a;main.py 介绍 什么是OCR&#xff1f; OCR是“Optical Charac…

德人合科技——@天锐绿盾 | -文档透明加密系统

天锐绿盾文档透明加密系统是一种先进的数据安全解决方案&#xff0c;旨在保护企业和组织的敏感信息&#xff0c;防止未经授权的访问和泄漏。 PC地址&#xff1a; https://isite.baidu.com/site/wjz012xr/2eae091d-1b97-4276-90bc-6757c5dfedee 以下是该系统的一些关键特点和功…

[C++11/14新特性] tuple元组介绍

C11 标准新引入了一种类模板&#xff0c;命名为 tuple&#xff08;中文可直译为元组&#xff09;。tuple 最大的特点是&#xff1a;实例化的对象可以存储任意数量、任意类型的数据。tuple 的应用场景很广泛&#xff0c;例如当需要存储多个不同类型的元素时&#xff0c;可以使用…

3D目标检测入门:探索OpenPCDet框架

前言 在自动驾驶和机器人视觉这两个飞速发展的领域中&#xff0c;3D目标检测技术扮演着核心角色。随着深度学习技术的突破性进展&#xff0c;3D目标检测算法的研究和应用正日益深入。OpenPCDet&#xff0c;这个由香港中文大学OpenMMLab实验室精心打造的开源工具箱&#xff0c;…

【用Python画画】六一儿童节画爱心

本文收录于 《Python编程入门》专栏&#xff0c;从零基础开始&#xff0c;分享一些Python编程基础知识&#xff0c;欢迎关注&#xff0c;谢谢&#xff01; 文章目录 一、前言二、代码示例三、知识点梳理四、总结 一、前言 本文介绍如何使用Python的海龟画图工具turtle&#xf…

堆排序的实现

在上一篇博客中&#xff0c;介绍了堆的实现&#xff0c;现在来介绍一下堆排序。 一.打印有序&#xff1a; 现在先给一个无序的数组&#xff0c;现在我们利用我们实现的堆的功能先完成一下打印排序&#xff1a; 在for循环里是一个建堆的过程&#xff0c;每来一个数据就放入堆中…

linux进程的加载和启动过程分析

我们的源代码通过预处理,编译,汇编,链接后形成可执行文件,那么当我们在终端敲下指令$ ./a.out argv1 argv2 后,操作系统是怎么将我们的可执行文件加载并运行的呢? 首先知道,计算机的操作系统的启动程序是写死在硬件上的,每次计算机上电时,都将自动加载启动程序,之后…

python第五次作业

1.请实现一个装饰器&#xff0c;每次调用函数时&#xff0c;将函数名字以及调用此函数的时间点写入文件中 # 导入datetime模块&#xff0c;用于获取当前时间并格式化输出 import datetime# 定义一个装饰器工厂函数log_funcName_time&#xff0c;它接受一个参数time def log_fu…

红外听力教学考试系统-红外语音听力广播在大学英语四六级听力考试中应用

红外听力教学考试系统-红外语音听力广播在大学英语四六级听力考试中的应用 由北京海特伟业科技有限公司任洪卓发布于2024年6月1日 红外语音听力广播&#xff08;即红外听力教学考试系统&#xff09;在英语四六级听力考试的应用正日益凸显出其重要性和优越性。在当前的高等教育…

xcode删除依赖包package,删除不必要的依赖项

点击项目&#xff0c;然后点击PROJECT项里面的Package DepenDependencies&#xff1a; 选中一个依赖项&#xff0c;然后点击减号&#xff0c;就可以把依赖项删除掉了&#xff0c;左侧项目下面的Package已经没有了这个依赖项 TARGET下面的package也要删除&#xff1a;在这里删除…

大数据分析统计

大数据分析统计 from datetime import datetimeimport pandas as pd import matplotlib.pyplot as pltpm25files [PM2.5_2021.csv, PM2.5_2022.csv, PM2.5_2023.csv] pm10files [PM10_2021.csv, PM10_2022.csv, PM10_2023.csv]def read_csv_file(files):# 每个文件都有表头…

C++之类(class)的三种成员修饰符(public、private、protected)总结

1、背景介绍 在C中&#xff0c;类&#xff08;class&#xff09;中成员的三种访问修饰符&#xff08;access specifiers&#xff09;用于控制类的成员&#xff08;属性和方法&#xff09;的访问权限。这些修饰符决定了类成员在类的外部和内部是否可以被访问。以下是这三种访问…

macOS上编译android的ffmpeg及ffmpeg.c

1 前言 前段时间介绍过使用xcode和qt creator编译调试ffmepg.c&#xff0c;运行平台是在macOS上&#xff0c;本文拟介绍下android平台如何用NDK编译链编译ffmepg库并使用。 macOS上使用qt creator编译调试ffmpeg.c macOS上将ffmpeg.c编译成Framework 大体思路&#xff1a; 其…

信息学奥赛初赛天天练-18-挑战程序阅读-最长公共子序列、字符串与数组越界的巧妙应用

PDF文档公众号回复关键字:20240601 1 2023 CSP-J 阅读程序2 阅读程序&#xff08;程序输入不超过数组成字符串定义的范围&#xff1a;判断题正确填√&#xff0c;错误填&#xff1b;除特殊说明外&#xff0c;判断题1.5分&#xff0c;选择题3分&#xff0c;共计40分&#xff…

Dijkstra求最短路篇二(全网最详细讲解两种方法,适合小白)(python,其他语言也适用)

前言&#xff1a; Dijkstra算法博客讲解分为两篇讲解&#xff0c;这两篇博客对所有有难点的问题都会讲解&#xff0c;小白也能很好理解。看完这两篇博客后保证收获满满。 第一篇博客讲解朴素Dijkstra算法Dijkstra求最短路篇一(全网最详细讲解两种方法&#xff0c;适合小白)(p…

计网ppt标黄知识点整理第(2)章节——谢希仁版本、期末复习自用

物理层考虑的是怎样才能在连接各种计算机的传输媒体上传输数据比特流&#xff0c;而不是指具体的传输媒体。4 个特性&#xff1a; 机械特性&#xff1a;指明接口所用接线器的形状和尺寸、引线数目和排列、固定和锁定装置等。 电气特性&#xff1a;指明在接口电缆的各条线上出现…

基于Springboot驾校预约平台小程序的设计与实现(源码+数据库+文档)

一.项目介绍 系统角色&#xff1a;管理员、教练、学员 小程序(仅限于学员注册、登录)&#xff1a; 查看管理员发布的公告信息 查看管理员发布的驾校信息 查看所有教练信息、预约(需教练审核)、评论、收藏喜欢的教练 查看管理员发布的考试信息、预约考试(需管理…

2024年东北师范CCPC

文章目录 A.Paper WateringB.nIM gAMEE.Checksum A.Paper Watering 思路&#xff1a;题目说有平方和开方两种操作&#xff0c;如果这个数是平方数&#xff0c;那么它开方之后就只能开方&#xff0c;如果平方的话就重复了&#xff0c;反之就有开方和平方两种操作。 代码如下 //…

为了方便看公众号文章,我搭建了个博客,在线看公众号所有历史文章,想看哪天的文章一秒就能找到

公众号没有个网页版的文章列表&#xff0c;只能在电脑和手机客户端看&#xff0c;想看之前的历史文章只能一直往下拉&#xff0c;想找某篇文章非常费劲。 为了方便看公众号文章&#xff0c;我搭建了个博客&#xff0c;博客地址https://sushengbuhuo.github.io/blog &#xf…

通过 SFP 接口实现千兆光纤以太网通信1

基于米联客ARTIX-7 系列开发板及其开发手册。 总体实现框图如下&#xff1a; SFP 接口 SFP 信号定义如下图所示。 Tri Mode Ethernet MAC 设置 由于使用千兆通讯&#xff0c;因此将速率设为 1Gbps。如下图所示。 首先&#xff0c;由于该 IP 需要与 IP 核 1G/2.5G Ethernet …