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

news2025/1/20 3:49:39

文章目录

    • 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.coloradmin.cn/o/1447215.html

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

相关文章

大数据 - Spark系列《五》- Spark常用算子

Spark系列文章&#xff1a; 大数据 - Spark系列《一》- 从Hadoop到Spark&#xff1a;大数据计算引擎的演进-CSDN博客 大数据 - Spark系列《二》- 关于Spark在Idea中的一些常用配置-CSDN博客 大数据 - Spark系列《三》- 加载各种数据源创建RDD-CSDN博客 大数据 - Spark系列《…

在Ubuntu上部署Stable Video Diffusion动画制作

Stable Diffusion团队推出的开源模型Stable Video Diffusion&#xff0c;支持生成约3秒的视频&#xff0c;分辨率为5761024。通过测试视频展示了其令人瞩目的性能&#xff0c;SVD模型是一个生成图像到视频的扩散模型&#xff0c;通过对静止图像的条件化生成短视频。其特点主要包…

AWD-Test2

1.已知账号密码&#xff0c;可SSH连接进行代码审计。2.登录可万能密码进入&#xff0c;也可注册后登录。3.修改url参数&#xff0c;发现报错。确定为Linux系统4.写入一句话&#xff0c;并提交。&#xff08;也可以文件上传&#xff0c;这里采用简洁的方法&#xff09; <?p…

书生·浦语大模型第四课作业

基础作业&#xff1a; 构建数据集&#xff0c;使用 XTuner 微调 InternLM-Chat-7B 模型, 让模型学习到它是你的智能小助手&#xff0c;效果如下图所示&#xff0c;本作业训练出来的模型的输出需要将不要葱姜蒜大佬替换成自己名字或昵称&#xff01; 1.安装 # 如果你是在 Int…

形态学操作之开操作与闭操作的python实现——数字图像处理

原理 图像处理中的开操作&#xff08;Opening&#xff09;和闭操作&#xff08;Closing&#xff09;是形态学&#xff08;Morphological&#xff09;操作的两个基本类型&#xff0c;它们都是基于膨胀&#xff08;Dilation&#xff09;和腐蚀&#xff08;Erosion&#xff09;操…

H12-821_31

31.下面是一台路由器的部分配置,关于该配置描述正确的是: A.源地址为1.1.1.1的数据包匹配第一条ACL语句rule 0,匹配规则为允许 B.源地址为1.1.1.3的数据包匹配第三条ACL语句rule 2,匹配规则为拒绝 C.源地址为1.1.1.4的数据包匹配第四条ACL语句rule 3,匹配规则为允许 D.源地址为…

【动态规划】:泰波那契模型_解码方法

朋友们、伙计们&#xff0c;我们又见面了&#xff0c;本专栏是关于各种算法的解析&#xff0c;如果看完之后对你有一定的启发&#xff0c;那么请留下你的三连&#xff0c;祝大家心想事成&#xff01; C 语 言 专 栏&#xff1a;C语言&#xff1a;从入门到精通 数据结构专栏&…

Codeforces Round 169 (Div. 2)C. Little Girl and Maximum Sum(差分、贪心)

文章目录 题面链接题意题解代码总结 题面 链接 C. Little Girl and Maximum Sum 题意 给q个[l,r]将所有这些区间里面的数相加和最大。 可以进行的操作是任意排列数组 题解 对出现的每个区间内的位置加上1&#xff0c;代表权值 操作完之后求一遍前缀和&#xff0c;得到每个…

通俗易懂搞定forEach和map的区别和使用

前言 在前端开发的时候&#xff0c;我们有时候需要对后端传过来的数组的进行相应的遍历处理&#xff0c;但是很多小伙伴对map和forEach两个方法的界限还是有模糊&#xff0c;本文从具体的示例来弄清楚两者的相同点和不同点 相同点 1.都是用于遍历数组的方法&#xff0c;可以…

关于氢能,什么是绿氢、蓝氢、灰氢?

今年3月,国家有关部门出台《氢能产业发展中长期规划(2021—2035年)》,明确了氢的能源属性,同时明确氢能是战略性新兴产业的重点方向是构建绿色低碳产业体系、打造产业转型升级的新增长点。一时间,氢能发展也受到了万众瞩目。我国目前已经成为世界最大的制氢国年制氢产量约…

L2-002 链表去重

一、题目 二、解题思路 结构体数组的下标表示该节点的地址&#xff0c;value 表示该节点的值&#xff0c;next 表示下一个结点的地址。result1 表示去重后的链表的节点的地址&#xff0c;result2 表示被删除的链表的节点的地址。 flag 表示节点对应的值是否出现过&#xff0c;…

【小赛1】蓝桥杯双周赛第5场(小白)思路回顾

我的成绩&#xff1a;小白(5/6) 完稿时间&#xff1a;2024-2-13 比赛地址&#xff1a;https://www.lanqiao.cn/oj-contest/newbie-5/ 相关资料&#xff1a; 1、出题人题解&#xff1a;“蓝桥杯双周赛第5次强者挑战赛/小白入门赛”出题人题解 - 知乎 (zhihu.com) 2、矩阵快速幂&…

《Java 简易速速上手小册》第9章:Java 开发工具和框架 (2024 最新版)

文章目录 9.1 Maven 和 Gradle - 构建与依赖管理的神兵利器9.1.1 基础知识9.1.2 重点案例&#xff1a;使用 Maven 构建 Spring Boot 应用9.1.3 拓展案例 1&#xff1a;使用 Gradle 构建多模块项目9.1.4 拓展案例 2&#xff1a;利用 Gradle Wrapper 确保构建的一致性 9.2 Spring…

【JavaEE Spring】Spring 原理

Spring 原理 1. Bean的作⽤域1.1 概念1.2 Bean的作⽤域 2. Bean的⽣命周期 1. Bean的作⽤域 1.1 概念 在Spring IoC&DI阶段, 我们学习了Spring是如何帮助我们管理对象的. 通过 Controller , Service , Repository , Component , Configuration ,Bean 来声明Bean对象。通…

数学建模:K-means聚类手肘法确定k值(含python实现)

原理 当K-means聚类的k值不被指定时&#xff0c;可以通过手肘法来估计聚类数量。   在聚类的过程中&#xff0c;随着聚类数的增大&#xff0c;样本划分会变得更加精细&#xff0c;每个类别的聚合程度更高&#xff0c;那么误差平方和&#xff08;SSE&#xff09;会逐渐变小&am…

备战蓝桥杯---图论基础理论

图的存储&#xff1a; 1.邻接矩阵&#xff1a; 我们用map[i][j]表示i--->j的边权 2.用vector数组&#xff08;在搜索专题的游戏一题中应用过&#xff09; 3.用邻接表&#xff1a; 下面是用链表实现的基本功能的代码&#xff1a; #include<bits/stdc.h> using nam…

那些 C语言指针 你不知道的小秘密 (完结篇)

本篇会加入个人的所谓‘鱼式疯言’ ❤️❤️❤️鱼式疯言:❤️❤️❤️此疯言非彼疯言 而是理解过并总结出来通俗易懂的大白话, 我会尽可能的在每个概念后插入鱼式疯言,帮助大家理解的. &#x1f92d;&#x1f92d;&#x1f92d;可能说的不是那么严谨.但小编初心是能让更多人能…

蓝桥杯嵌入式第11届真题(完成) STM32G431

蓝桥杯嵌入式第11届真题(完成) STM32G431 题目 代码 程序和之前的大同小异&#xff0c;不过多解释 main.c /* USER CODE BEGIN Header */ /********************************************************************************* file : main.c* brief :…

第4讲 小程序首页实现

首页 create.vue <template><view class"vote_type"><view class"vote_tip_wrap"><text class"type_tip">请选择投票类型</text><!-- <text class"share">&#xe739;分享给朋友</text&g…

免费分享一套PyQt6学生信息管理系统 Python管理系统 Python源码,挺漂亮的

大家好&#xff0c;我是java1234_小锋老师&#xff0c;看到一个不错的PyQt6学生信息管理系统 Python管理系统 Python源码&#xff0c;分享下哈。 项目视频演示 【免费】PyQt5 学生信息管理系统 Python管理系统 Python源码 Python毕业设计_哔哩哔哩_bilibili【免费】PyQt5 学生…