代码随想录刷题笔记 DAY 25 | 组合问题 No.77 | 组合求和III No.216 | 电话号码的字母组合 No.17

文章目录

    • Day 25
      • 01. 组合问题(No. 77)
        • 2.1 题目
        • 2.2 笔记
        • 2.3 代码
      • 02. 组合求和III(No. 216)
        • 2.1 题目
        • 2.2 笔记
        • 2.3 代码
      • 03. 电话号码的字母组合(No. 17)
        • 3.1 题目
        • 3.2 笔记
        • 3.3 代码
        • 3.4 补充

Day 25

01. 组合问题(No. 77)

2.1 题目

给定两个整数 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
2.2 笔记

本题的常规解法在昨天的题解中已经写出

代码随想录刷题笔记 DAY 24 | 回溯算法理论基础 | 组合问题 No. 77

这里来讲解一下本题的剪枝优化

假设 n = 4k = 4

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

for (int i = startIndex; i <= n; i++) {path.add(i);backtracking(n, k, i+1);path.remove(path.size() - 1); // 回溯删除节点
}

startIndex == 2 的时候,后面能取得的数字为 3 4 即遍历完所有的取值数目也不可能达到题目要求的 k

所以对上面除了 1 2 3 4 这条线都应该通过剪枝去除,因为遍历它们没有意义。

当确定了一个 i 那这条路线能取得的最多的数字个数就确认了,也就是 n - i + 1

当取到这个节点的时候 path 内共有 path.size() 个元素,所以从这个路线中能取得的 最大 数目为
N m = n − i + 1 − p a t h . s i z e ( ) N_m = n - i + 1 - path.size() Nm=ni+1path.size()
如果这条路线能够取得总数 k,那可以得出
N m ≥ k N_m \ge k Nmk
最终能够推出
i ≤ n − k + 1 − p a t h . s i z e ( ) i \le n - k + 1-path.size() ink+1path.size()
这时候的 i 才是 有意义i

所以 for 循环的终止条件应该改为上式

2.3 代码
class Solution {List<Integer> path = new ArrayList<>();List<List<Integer>> res = new ArrayList<>();public List<List<Integer>> combine(int n, int k) {backtracking(n, k, 1);return res;}public void backtracking(int n, int k, int startIndex) {if (path.size() == k) {res.add(new ArrayList<>(path));return;}for (int i = startIndex; i <= (n - k + path.size() + 1); i++) {path.add(i);backtracking(n, k, i+1);path.remove(path.size() - 1);}}
}

02. 组合求和III(No. 216)

2.1 题目

找出所有相加之和为 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
2.2 笔记

如果做过组合问题,这道题目就非常容易了,思路和剪枝操作都是完全相同的,就只需要注意一下递归的终点。

因为本题有两个限制条件

  • 数字的总数是 k
  • 数字的和是 n

所以当判断出 sum > k 的时候也要记得结束递归

2.3 代码
class Solution {int temp = 0;List<Integer> path = new ArrayList<>();List<List<Integer>> res = new ArrayList<>();public List<List<Integer>> combinationSum3(int k, int n) {backtracking(k, n, 1);return res;}public void backtracking(int k, int n, int startIndex) {if (temp > n) {return;}if (path.size() == k && temp == n) {res.add(new ArrayList(path));}for (int i = startIndex; i <= (9 - k + path.size() + 1); i++) {path.add(i);temp += i;backtracking(k, n, i+1);temp -= i;path.remove(path.size() - 1);}}
}

03. 电话号码的字母组合(No. 17)

题目链接

代码随想录题解

3.1 题目

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

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

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

示例 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'] 的一个数字。
3.2 笔记

先给出这道题的回溯解法:

在大多数的题目中回溯的作用就是提供一个层数可控的 for 循环来暴力解决这个问题,所以当某道题目没有思路的时候就先向 for 循环的方向思考。

❓ 这道题目用 for 循环应该如何解答呢?

💡 假如说只按了两个数字,23,首先将 数字映射为字符数组,再去求这 两个数组 的组合,那肯定很容易,两层 for 循环就可以解决。

for (String a : arr1) {for (String b : arr2) {		}
}

通过这样的形式就能求出所有的组合。

那三个按键、五个按键该怎么解决呢?

这就需要回溯法来解决这个问题了,大家遇到这道题没思路的原因很大概率是没接触过这种每层的分枝操作的 不是同一个数组

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

所以要做的就是在每层遍历完后去改变 for 循环中遍历的数组,这就是形成本题目要求的树形结构的方法。

可以在每次递归(前往下一层)的时候传递一个标识,用这个标识来确定 本层 遍历的数组是哪一个。

这里定为 index,从 0 开始,直到遍历完 所有的按键结束,也就是 index > 按下的按键总数

如何通过 index 来定位到遍历的是 哪些 字母呢?

  • 因为数字和字母存在着映射的关系,所以可以提前准备好所有的映射关系

    static Map<Character, String[]> NumMap = new HashMap<>();
    static {NumMap.put('2', new String[]{"a", "b", "c"});NumMap.put('3', new String[]{"d", "e", "f"});NumMap.put('4', new String[]{"g", "h", "i"});NumMap.put('5', new String[]{"j", "k", "l"});NumMap.put('6', new String[]{"m", "n", "o"});NumMap.put('7', new String[]{"p", "q", "r", "s"});NumMap.put('8', new String[]{"t", "u", "v"});NumMap.put('9', new String[]{"w", "x", "y", "z"});}
    
  • 接下来将输入的字符串转为字符数组,index 的意义就是这个字符数组的下标

    globalArr = digits.toCharArray();
    
  • 这样通过下标找到当前层是哪个数字,再通过 数字和字母的映射关系 就直到当前层遍历的字符串数组

3.3 代码
class Solution {char[] globalArr; // 存储传入的按键StringBuilder temp = new StringBuilder(); // 路径变量List<String> res = new ArrayList<>();static Map<Character, String[]> NumMap = new HashMap<>();static {NumMap.put('2', new String[]{"a", "b", "c"});NumMap.put('3', new String[]{"d", "e", "f"});NumMap.put('4', new String[]{"g", "h", "i"});NumMap.put('5', new String[]{"j", "k", "l"});NumMap.put('6', new String[]{"m", "n", "o"});NumMap.put('7', new String[]{"p", "q", "r", "s"});NumMap.put('8', new String[]{"t", "u", "v"});NumMap.put('9', new String[]{"w", "x", "y", "z"});}public List<String> letterCombinations(String digits) {globalArr = digits.toCharArray();if (globalArr.length == 0) {return new ArrayList<>();}backtracking(0);return res;}public void backtracking(int index) {if (index > globalArr.length - 1) {res.add(temp.toString());return;}// 获取本层遍历的是哪个字符数组String[] letterArr = NumMap.get(globalArr[index]);for (String s : letterArr) {temp.append(s);backtracking(++index);temp.deleteCharAt(temp.length() - 1);   index--;}}
}
3.4 补充

其实这道题目我一开始做的时候使用的是另一种方法。

以 按键 234 为例,本题其实就是求 23 的所有组合 x,再求 x4 的所有组合。

所以先编写一个实现两两组合的代码,再通过遍历将所有的按键全部组合起来也能得到结果。

class Solution {// 映射关系static Map<Character, String[]> NumMap = new HashMap<>();static {NumMap.put('2', new String[]{"a", "b", "c"});NumMap.put('3', new String[]{"d", "e", "f"});NumMap.put('4', new String[]{"g", "h", "i"});NumMap.put('5', new String[]{"j", "k", "l"});NumMap.put('6', new String[]{"m", "n", "o"});NumMap.put('7', new String[]{"p", "q", "r", "s"});NumMap.put('8', new String[]{"t", "u", "v"});NumMap.put('9', new String[]{"w", "x", "y", "z"});}public List<String> letterCombinations(String digits) {char[] charArray = digits.toCharArray();// 边界情况的处理:字符个数不足两个if (charArray.length == 1) {return Arrays.stream(NumMap.get(charArray[0])).toList();} else if (charArray.length == 0) {return new ArrayList<>();}// 将 temp 与其他字符依次两两组合String[] temp = getTwoCombinations(NumMap.get(charArray[0]), NumMap.get(charArray[1]));for (int i = 2; i < charArray.length; i++) {temp = getTwoCombinations(temp, NumMap.get(charArray[i]));}return Arrays.stream(temp).toList();}/**实现两两组合*/public String[] getTwoCombinations(String[] a, String[] b) {String[] res = new String[a.length * b.length];int n = 0;for (String string : a) {String temp = string;for (String s : b) {temp += s;res[n++] = temp;temp = string;}}return res;}
}   

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

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

相关文章

matplotlib画简单的论文图像

由于最近论文里需要插入绘图&#xff0c;因此写一篇博客记录一下 折曲线图 基本绘图 在matplotlib中折线和曲线图是最常用和最简单的图。只需要直接使用方法plot即可。 import matplotlib.pyplot as plt plt.plot(x,y) plt.show()其中上述的代码中x&#xff0c;y分别是横坐…

剑指offer——二进制中1的个数

目录 1. 题目描述2. 可能引起死循环的想法3. 改进后的代码4. 给面试官惊喜的代码 1. 题目描述 请实现一个函数&#xff0c;输入一个整数&#xff0c;输出该数二进制表示中1的个数。例如把9表示成二进制位1001&#xff0c;有2位是1&#xff0c;因此如果输入9&#xff0c;该函数输…

C#,最长公共扩展(LCE,Longest Common Extention)的算法与源代码

一、最长公共扩展&#xff08;LCE&#xff09;问题 考虑一个字符串s&#xff0c;并为每对&#xff08;L&#xff0c;R&#xff09;计算从L和R开始的s的最长子字符串。 在LCE中&#xff0c;在每个查询中&#xff0c;我们必须回答从索引L和R开始的最长公共前缀的长度。 例子&am…

机器学习、深度学习、强化学习、迁移学习的关联与区别

Hi&#xff0c;大家好&#xff0c;我是半亩花海。本文主要了解并初步探究机器学习、深度学习、强化学习、迁移学习的关系与区别&#xff0c;通过清晰直观的关系图展现出四种“学习”之间的关系。虽然这四种“学习”方法在理论和应用上存在着一定的区别&#xff0c;但它们之间也…

什么是 Flet?

什么是 Flet&#xff1f; Flet 是一个框架&#xff0c;允许使用您喜欢的语言构建交互式多用户 Web、桌面和移动应用程序&#xff0c;而无需前端开发经验。 您可以使用基于 Google 的 Flutter 的 Flet 控件为程序构建 UI。Flet 不只是“包装”Flutter 小部件&#xff0c;而是…

51单片机编程基础(C语言):电子时钟(LED1602作为显示)

题目要求&#xff1a; 审题时这个题是用数码管来显示的&#xff0c;数码管显示时钟我完成了一个&#xff0c;只是要求跟他不一样&#xff0c;所以这次想用LCD1602来显示&#xff0c;所以我先用LCD1602完成&#xff0c;再用数码管完成&#xff08;其实也只要在我之前的项目基础…

《数电》理论笔记-第3章-常用组合逻辑电路及MSI组合电路模块的应用

一&#xff0c;编码器和译码器 1&#xff0c;编码器 编码:用由0和1组成的代码表示不同的事物。 编码器:实现编码功能的电路&#xff0c; 常见编码器:普通编码器、优先编码器、二进制编码器二-十进制编码器等等 1.1 三位二进制普通编码器和三位二进制优先编码器 1分58秒开始 …

洛谷_P1923 【深基9.例4】求第 k 小的数_python写法

哪位大佬可以出一下这个的题解&#xff1f;&#xff1f;&#xff1f;&#xff1f;&#xff1f;话说蓝桥杯可以用numpy库吗&#xff1f;&#xff1f;&#xff1f;&#xff1f;&#xff1f;&#xff1f; 这道题有一个很简单的思路就是排序完成之后再访问。 but有很大的问题&…

近十年金融资产收益率

通过掌握大类资产的历年收益率数据&#xff0c;做基于数据的投资&#xff0c;提高胜率和收益率。 下面是同花顺梳理的2014至2023大类金融资产收益率&#xff1a; 基于这个数据&#xff0c;我们再统计两项指标&#xff1a; 1. 每种资产在近十年的投资胜率&#xff08;收益率为…

哈希表 ?

哈希表 首先什么是 哈希表&#xff0c;哈希表&#xff08;英文名字为Hash table&#xff0c;国内也有一些算法书籍翻译为散列表&#xff0c;大家看到这两个名称知道都是指hash table就可以了&#xff09;。 哈希表是根据关键码的值而直接进行访问的数据结构。 这么这官方的解释…

每日一练——月落乌啼算钱

题目&#xff1a; 举例&#xff1a; 输入&#xff1a;6&#xff0c;输出&#xff1a;8.00 最开始看到这道题还有点蒙&#xff0c;但是看到他的公式想起了斐波那契数列 1,1,2,3,5,8...... 由前两个数相加得到第三个数&#xff0c;为An2An1An。 可以得出这个题目中所给的通项就…

Spark编程实验六:Spark机器学习库MLlib编程

目录 一、目的与要求 二、实验内容 三、实验步骤 1、数据导入 2、进行主成分分析&#xff08;PCA&#xff09; 3、训练分类模型并预测居民收入 4、超参数调优 四、结果分析与实验体会 一、目的与要求 1、通过实验掌握基本的MLLib编程方法&#xff1b; 2、掌握用MLLib…