算法day21|回溯理论基础、77. 组合(剪枝)、216.组合总和III、17.电话号码的字母组合

news/2024/9/17 7:37:25/ 标签: 算法, 剪枝, java, 数据结构, c++, leetcode

算法day21|回溯理论基础、77. 组合、216.组合总和III、17.电话号码的字母组合

  • 回溯理论基础
  • 77. 组合
  • 77.组合(剪枝改进版)
  • 216.组合总和III
  • 17.电话号码的字母组合

回溯理论基础

  • 回溯是递归的副产品,回溯函数也就是递归函数

  • 回溯属于暴力解法,并不是高效的算法,使用剪枝操作可以优化,但是依然不高效

  • 回溯本质上穷举,穷举所有所有的可能性,不放过任何一种情况。

  • 所有的回溯问题都可以写成树形结构,用递归表示深度,用每个结点的子集来表示宽度并用for循环遍历。最后一般是再终止条件出返回。

  • 可以解决的问题:

    • 组合问题:N个数里面按一定规则找出k个数的集合
    • 切割问题:一个字符串按一定规则有几种切割方式
    • 子集问题:一个N个数的集合里有多少符合条件的子集
    • 排列问题:N个数按一定规则全排列,有几种排列方式
    • 棋盘问题:N皇后,解数独等等
  • 模板:

  void backtracking(参数) {if (终止条件) {存放结果;return;}for (选择:本层集合中元素(树中节点孩子的数量就是集合的大小)) {处理节点;backtracking(路径,选择列表); // 递归回溯,撤销处理结果}}

注意点:

  • 返回值一般为void
  • 参数很难一开始就完全确定,需要边写边加

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 {
public:vector<int> path;vector<vector<int>> result;void backtracking(int n, int k,int startIndex){if(path.size()==k){result.push_back(path);return;}for(int i=startIndex;i<=n;i++){path.push_back(i);backtracking(n,k,i+1);path.pop_back();}return;}vector<vector<int>> combine(int n, int k) {backtracking(n,k,1);return result;}
};

首先要自己画一个树形结构,不能光靠脑洞来想。如图(该图来自卡哥):

77.组合1

一次递归回溯完成的事:一开始在一个集合里面取一个数并放在path数组中,中间一般是递归,在最后在把在本层递归里面取的数弹出数组。也就是一次递归实际上就是对应图中的一个方框(即集合)。有多少个方框(集合)就有多少个过程递归,当然不含最后的终止条件递归的。

终止条件:与一些二叉树的题目类似,在终止条件记录最终要求的结果。

本题的回溯主要体现在pop的过程,其他逻辑与正常的递归类似

77.组合(剪枝改进版)

class Solution {
public:vector<int> path;vector<vector<int>> result;void backtracking(int n, int k,int startIndex){if(path.size()==k){result.push_back(path);return;}for(int i=startIndex;i<=n-(k-path.size())+1;i++){path.push_back(i);backtracking(n,k,i+1);path.pop_back();}return;}vector<vector<int>> combine(int n, int k) {backtracking(n,k,1);return result;}
};

最大的区别就是for循环将 i<=n 改成了 i<=n-(k-path.size())+1,其中 k-path.size()表示最后的结果还需要k-path.size()个数,所以用**n-(k-path.size())**作为遍历的终点。如果不理解,可以先记住。

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 {
public:vector<int> path;vector<vector<int>> result;int vectorSum(vector<int> vec){int sum=0;for(int i=0;i<vec.size();i++)sum+=vec[i];return sum;}void backtracking(int k, int n, int startIndex){if(path.size()==k){if(vectorSum(path)==n)result.push_back(path);return;}for(int i=startIndex;i<=9-(k-path.size())+1;i++){path.push_back(i);backtracking(k,n,i+1);path.pop_back();}return;}vector<vector<int>> combinationSum3(int k, int n) {backtracking(k,n,1);return result;}
};

17.电话号码的字母组合

给定一个仅包含数字 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'] 的一个数字。
class Solution {
public:string letterMap[10]={" "," ","abc","def","ghi","jkl","mno","pqrs","tuv","wxyz"};string path;vector<string> result;void backtracking(string digits,int index){if(index==digits.size()){result.push_back(path);return;}int start=digits[index]-'0';string letter=letterMap[start];for(int i=0;i<letter.size();i++){path.push_back(letter[i]);backtracking(digits,index+1);path.pop_back();}return;}vector<string> letterCombinations(string digits) {if(digits=="")return result;backtracking(digits,0);return result;}
};

这题主要是两个难点:

  • 如何将digits内的数字取出来,并通过这个数字来映射字母呢?

答:首先引入index作为字符串digits的索引,用于对digits的遍历。当得到如digits[0]之后,用特定语法将其转化为int,即减去 ’0‘,字符型即可变成整数型如:

int start=digits[index]-'0';

然后,得到数字之后,建立建立二维数组,也就是字符串型的一维数组:

string letterMap[10]={" "," ","abc","def","ghi","jkl","mno","pqrs","tuv","wxyz"};

(要有这个意识:字符串本身就是一维数组,内部的数据类型是字符型,每一项都是字符,而整体是字符串)所以这里的字符串可以当成是二维数组。

  • 如何在多个不同集合内做递归回溯

答:我们之前都是在一个集合里面折腾,这次其实是多个不同集合,该怎么办呢?正确的思路:寻找他们的根源。读题发现,他们都来自于字符串digits,只要能对digits做一些处理,就完全可能实现递归回溯。

巧思:

backtracking(digits,index+1);

直接在函数里面加减,更加精巧灵动,又学了一招。


http://www.ppmy.cn/news/1522365.html

相关文章

H5 响应式精品网站推荐导航源码

源码名称&#xff1a;响应式精品网站推荐导航源码 源码介绍&#xff1a;一款响应式精品网站推荐导航源码&#xff0c;可以自己修改代码替换图标图片和指向网址。背景图支持自动替换&#xff0c;背景图可以在img.php中修改 需求环境&#xff1a;H5 下载地址&#xff1a; http…

多语言融合,全栈操控Vue + Spring Boot + SQL Server + Python部署到Windows服务器!

将一个包含Vue前端、Spring Boot后端、SQL Server数据库和Python脚本的项目部署到Windows服务器上涉及多个步骤。以下是一个详细的指南&#xff0c;帮助您完成这一过程。 前言 你是否正在寻找将Vue, Spring Boot, SQL Server和Python完美融合&#xff0c;并顺利部署到Windows服…

JS中【记忆函数】内容详解与应用

在 JavaScript 中&#xff0c;记忆函数&#xff08;Memoization&#xff09;是一种优化技术&#xff0c;旨在通过存储函数的调用结果&#xff0c;避免重复计算以提高性能。它非常适用于纯函数&#xff08;同样的输入总是产生同样的输出&#xff09;&#xff0c;特别是在需要大量…

计算机电脑共享文件和打印机共享问题:“计算机无法访问!您可能没有权限使用网络资源。请与这台服务器的管理员联系以查明您是否有访问权限。”解决办法

在Win10系统中&#xff0c;我们在访问局域网共享文件或计算机共享打印机的时候会出现“你可能没有权限使用网络资源 ”。请与这台服务器的管理员联系以查明你是的提示&#xff0c;很多用户不知道如何解决&#xff0c;下面就把正确的解决方法分享给大家&#xff0c;你可能没有权…

东土科技:TSN与AUTBUS技术融合创新,聚自主力量推新质发展

在即将于厦门举办的2024金砖国家新工业革命展——工业互联网展区中&#xff0c;北京东土科技股份有限公司&#xff08;以下简称“东土科技”&#xff09;将携其尖端技术成果&#xff0c;以“TSN与AUTBUS技术融合创新&#xff0c;聚自主力量推新质发展”为主题闪耀亮相。作为工业…

【Kubernetes】K8s 的安全框架和用户认证

K8s 的安全框架和用户认证 1.Kubernetes 的安全框架1.1 认证&#xff1a;Authentication1.2 鉴权&#xff1a;Authorization1.3 准入控制&#xff1a;Admission Control 2.Kubernetes 的用户认证2.1 Kubernetes 的用户认证方式2.2 配置 Kubernetes 集群使用密码认证 Kubernetes…

【计算机毕业设计】微信小程序的美甲店铺座位预约系统

摘要&#xff1a; 随着科技的不断发展&#xff0c;社会经济的快速发展&#xff0c;人们的生活水平不断提高&#xff0c;美容美发行业也随之繁荣。然而&#xff0c;传统的美甲店铺座位预约方式已经无法适应现代化的需求&#xff0c;需求者需要更加便捷快速的预约方式。本论文基…

ROADM(可重构光分插复用器)-介绍

1. 引用 https://zhuanlan.zhihu.com/p/163369296 https://zhuanlan.zhihu.com/p/521352954 https://zhuanlan.zhihu.com/p/91103069 https://zhuanlan.zhihu.com/p/50610236 术语&#xff1a; 英文缩写描述灰光模块彩光模块CWDM&#xff1a;Coarse Wave-Length Division …

Redis-主从集群

主从架构 单节点Redis的并发能力是有上限的&#xff0c;要进一步提高Redis的并发能力&#xff0c;就需要搭建主从集群&#xff0c;实现读写分离。 主从数据同步原理 全量同步 主从第一次建立连接时&#xff0c;会执行全量同步&#xff0c;将master节点的所有数据都拷贝给sla…

卷积神经网络(一)

目录 一.卷积神经网络的组成 二.卷积层 目的: 参数: 计算公式 卷积运算过程 三.padding-零填充 1.Valid and Same卷积 2.奇数维度的过滤器 四.stride步长 五.多通道卷积 1.多卷积核(多个Filter) 六.卷积总结 七.池化层(Pooling) 八.全连接层 都看到这里了,点个…

【超简单】1分钟解决ppt全文字体一键设置

省流 ppt的全部字体需要在“幻灯片母版”里面&#xff0c;“自定义字体”去设置好标题与正文的字体之后才算全部设置完毕 “视图”---“幻灯片母版” 找到“字体”---“自定义字体” 设置好中文和西文的字体&#xff0c;都可以按照自己的选择来&#xff0c;保存即可 吐槽 之…

以太网--TCP/IP协议(一)

概述 以太网是局域网的一种&#xff0c;其他的比如还有令牌环、FDDI。和局域网对应的就是广域网&#xff0c;如Internet&#xff0c;城域网等。 从网络层次看&#xff0c;局域网协议主要偏重于低层&#xff08;业内一般把物理层、数据链路层归为低层&#xff09;。以太网协议…

Unity 热更 之 【YooAsset 热更】几分钟快速了解 YooAsset [功能面板]、以及 [基础代码] 说明

Unity 热更 之 【YooAsset 热更】几分钟快速了解 YooAsset [功能面板]、以及 [基础代码] 说明 目录 Unity 热更 之 【YooAsset 热更】几分钟快速了解 YooAsset [功能面板]、以及 [基础代码] 说明 一、简单介绍 二、系统需求 三、快速引入工程中 四、功能面板 全局配置 Yoo…

OGRE 3D----创建第一个OGRE 3D示例

目录 1. OGRE 3D概述 2. OGRE 3D vs VTK 3. 编译OGRE 3D 源码 4. 创建示例和配置其编译环境 5. 配置示例程序的执行环境 1. OGRE 3D概述 OGRE (Object-Oriented Graphics Rendering Engine) 是一个开源的、高级的 3D 图形渲染引擎&#xff0c;它提供了一个抽象层&#xf…

linux服务器之top命令详解

top&#xff1a;系统资源管理器 top命令类似于windows的任务管理器&#xff0c;可以查看内存、cpu、进程等信息(动态查看系统资源信息)在linux系统中常用top命令查看资源性能分析工具 一、参数释义&#xff1a; 第一行 系统时间和平均负载 top&#xff1a;名称22:12:46&#…

【笔记】数据结构刷题09

快速排序 215. 数组中的第K个最大元素 class Solution { public:int findKthLargest(vector<int>& nums, int k) {return divide(nums,0,nums.size()-1,nums.size()-k);}int divide(vector<int>& nums,int left,int right,int k){if(leftright)return nums…

Linux CentOS 7.9 安装mysql8

1、新建mysql文件夹 数据比较大&#xff0c;所以我在服务器另外挂了一个盘装mysql&#xff0c;和默认安装一个道理&#xff0c;换路径即可 cd ../ //创建文件夹 mkdir mysql //进入mysql文件夹 cd mysql 2、下载mysql8.0安装包并解压、重命名 //下载安装包 wget https://dev…

[JAVA基础知识汇总-1] 创建线程的几种方式(含线程池相关)

文章目录 1. 继承Thread类2. 实现Runnable接口3. 实现Callable接口4. 线程池4.1 利用Executors工具类来创建线程池4.2 为什么不建议使用Executors来创建线程池&#xff1f;4.3 ThreadPoolExecutor是线程池的核心实现类&#xff0c;可以利用它来创建线程池4.4 线程池的状态 可以…

Android 开发避坑经验第四篇:正确处理Activity和Fragment的状态保存与恢复

在 Android 开发中,​​Activity​​ 和 ​​Fragment​​ 的状态保存与恢复是一个常见的坑点。如果处理不当,可能会导致应用在屏幕旋转、后台恢复等场景下出现数据丢失、UI 状态不一致等问题。本篇文章将详细探讨如何正确保存和恢复 ​​Activity​​ 与 ​​Fragment​​ 的…

数学基础 -- 线性代数之LU分解

LU分解 LU分解&#xff08;LU Decomposition&#xff09;是线性代数中非常重要的一种矩阵分解方法。它将一个方阵分解为一个下三角矩阵&#xff08;L矩阵&#xff09;和一个上三角矩阵&#xff08;U矩阵&#xff09;的乘积。在数值线性代数中&#xff0c;LU分解广泛用于求解线…