代码随想录算法训练营第二十五天|17.电话号码的字母组合、39.组合总和、40.组合总和Ⅲ

文档链接:https://programmercarl.com/

LeetCode17.电话号码的字母组合

题目链接:​​​​​​​https://leetcode.cn/problems/letter-combinations-of-a-phone-number/

思路:

理解本题后,要解决如下三个问题:

  1. 数字和字母如何映射——可以使用map或二维数组做数字和字母表的映射
  2. 两个字母就两个for循环,三个字符我就三个for循环,以此类推,然后发现代码根本写不出来——n个for循环的问题就要考虑回溯

来看参数,参数指定是有题目中给的string digits,然后还要有一个参数就是int型的index。

注意这个index可不是 77.组合 (opens new window)和216.组合总和III (opens new window)中的startIndex了。

这个index是记录遍历第几个数字了,就是用来遍历digits的(题目中给出数字字符串),同时index也表示树的深度。

注意这里for循环,可不像是在回溯算法:求组合问题! (opens new window)和回溯算法:求组合总和! (opens new window)中从startIndex开始遍历的

因为本题每一个数字代表的是不同集合,也就是求不同集合之间的组合,而77. 组合 (opens new window)和216.组合总和III (opens new window)都是求同一个集合中的组合!

回溯:

class Solution {
public:string s;vector<string> result;string letterMap[10] = {"", "", "abc", "def", "ghi", "jkl", "mno", "pqrs", "tuv", "wxyz"};void backtracking(string digits, int index) {if(index == digits.size()) {result.push_back(s);return ;}int digit = digits[index] - '0';string letters = letterMap[digit];for(int i = 0; i < letters.size(); i++) {s.push_back(letters[i]);backtracking(digits, index + 1);s.pop_back();}}vector<string> letterCombinations(string digits) {if(digits.size() == 0) return result;backtracking(digits, 0);return result;}
};

LeetCode39.组合总和

题目链接:https://leetcode.cn/problems/combination-sum/

思路:同组合Ⅲ一样。注意题目说可以重复选,那么startIndex就应该每次都从i开始,而不再是i+1。

什么时候需要用startIndex呢?如果是一个集合来求组合的话,就需要startIndex。如果是多个集合取组合,各个集合之间相互不影响,那么就不用startIndex

回溯:

class Solution {
public:vector<int> path;vector<vector<int>> result;void backtracking(vector<int>& candidates, int target, int sum, int startIndex) {if(sum > target) return ;if(sum == target) {result.push_back(path);return ;}for(int i = startIndex; i < candidates.size(); i++) {path.push_back(candidates[i]);sum += candidates[i];backtracking(candidates, target, sum, i);sum -= candidates[i];path.pop_back();}}vector<vector<int>> combinationSum(vector<int>& candidates, int target) {path.clear();result.clear();backtracking(candidates, target, 0, 0);return result;}
};

剪枝优化:必须要注意的是前提这个数组是有序的!

对于sum已经大于target的情况,其实是依然进入了下一层递归,只是下一层递归结束判断的时候,会判断sum > target的话就返回。

其实如果已经知道下一层的sum会大于target,就没有必要进入下一层递归了。

那么可以在for循环的搜索范围上做做文章了。

对总集合排序之后,如果下一层的sum(就是本层的 sum + candidates[i])已经大于target,就可以结束本轮for循环的遍历

class Solution {
public:vector<int> path;vector<vector<int>> result;void backtracking(vector<int>& candidates, int target, int sum, int startIndex) {if(sum == target) {result.push_back(path);return ;}for(int i = startIndex; i < candidates.size() && sum + candidates[i] <= target; i++) {path.push_back(candidates[i]);sum += candidates[i];backtracking(candidates, target, sum, i);sum -= candidates[i];path.pop_back();}}vector<vector<int>> combinationSum(vector<int>& candidates, int target) {path.clear();result.clear();sort(candidates.begin(), candidates.end());backtracking(candidates, target, 0, 0);return result;}
};

LeetCode40.组合总和Ⅲ

题目链接:https://leetcode.cn/problems/combination-sum-ii/

思路:题目给的数组中包含重复元素,既要注意树层去重,又要防止树枝去重。要想到用一个used数组来存储用过的还是蛮难想的。

本题的难点在于:集合(数组candidates)有重复元素,但还不能有重复的组合

回溯:

class Solution {
public:vector<int> path;vector<vector<int>> result;void backtracking(vector<int>& candidates, int target, int sum, int startIndex, vector<int>& used) {if(sum == target) {result.push_back(path);return ;}for(int i = startIndex; i < candidates.size() && sum + candidates[i] <= target; i++) {if(i > 0 && candidates[i] == candidates[i - 1] && used[i - 1] == 0) continue;path.push_back(candidates[i]);sum += candidates[i];used[i] = 1;backtracking(candidates, target, sum, i + 1, used);path.pop_back();sum -= candidates[i];used[i] = 0;}}vector<vector<int>> combinationSum2(vector<int>& candidates, int target) {vector<int> used(candidates.size(), 0);sort(candidates.begin(), candidates.end());backtracking(candidates, target, 0, 0, used);return result;}
};

还可以不使用used数组,直接用startIndex来控制横向for循环(个人感觉相比used数组更简单点,而且容易想到)

class Solution {
private:vector<vector<int>> result;vector<int> path;void backtracking(vector<int>& candidates, int target, int sum, int startIndex) {if (sum == target) {result.push_back(path);return;}for (int i = startIndex; i < candidates.size() && sum + candidates[i] <= target; i++) {// 要对同一树层使用过的元素进行跳过if (i > startIndex && candidates[i] == candidates[i - 1]) {continue;}sum += candidates[i];path.push_back(candidates[i]);backtracking(candidates, target, sum, i + 1); // 和39.组合总和的区别1,这里是i+1,每个数字在每个组合中只能使用一次sum -= candidates[i];path.pop_back();}}

总结:感觉回溯在我脑海里已经有点印象了。

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

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

相关文章

mongodb sharding分片模式的集群数据库,日志治理缺失导致写入数据库报错MongoWriteConcernException的问题总结(下)

一、接着上文 上文介绍了mongodb sharding的分片集群搭建&#xff0c;本文侧重于讲述日志治理。 这里使用linux自带的日志治理工具logrotate&#xff0c;无论是哪个端口的进程&#xff0c;其日志治理方式类似。 查看/data目录下的文件大小&#xff0c; du -hs *二、Logrota…

每日一题(相交链表 )

欢迎大家来我们主页进行指导 LaNzikinh-CSDN博客 160. 相交链表 - 力扣&#xff08;LeetCode&#xff09; 给你两个单链表的头节点 headA 和 headB &#xff0c;请你找出并返回两个单链表相交的起始节点。如果两个链表不存在相交节点&#xff0c;返回 null 。 图示两个链表在节…

linux 中的syslog的含义和用法

在Linux系统中&#xff0c;syslog是一种系统日志服务&#xff0c;用于收集、存储和管理系统和应用程序生成的日志消息。syslog服务负责记录系统的运行状态、错误信息、警告、调试信息等&#xff0c;以便系统管理员可以监控系统的健康状况、故障排查和性能优化。 含义和作用&am…

RUST使用crates.io上的依赖完整教程

1.打开crates.io 2.搜索要使用的依赖,如rand 点击包名,进入包详情页面: 添加依赖方法有两种 1.使用cargo命令 2.直接修改Cargo.toml 使用cargo命令操作如下: 在工程目录执行如下命令: cargo add rand 执行完成后如自动向Cargo.toml中添加依赖如下: 手动修改Cargo.toml是…

漏洞挖掘 | ruoyi框架管理系统漏洞

前言&#xff1a; 在挖src的时候&#xff0c;可以通过信息收集收集弱口令&#xff0c;然后通过后台弱口令进入后台&#xff1a; 发现一个弱口令进去后&#xff1a; 【魔方老师提醒才发现&#xff0c;这个蓝色的草丛其实可以大致判断是若依系统】 看这界面&#xff0c;是不是…

XSS伪协议

XSS伪协议简介 XSS&#xff08;跨站脚本攻击&#xff09;中的伪协议是指利用一些浏览器允许的特殊协议来执行恶意脚本的一种方式。常见的伪协议包括 javascript:, data:, vbscript: 等。 攻击者可以通过构造特定的URL&#xff0c;将恶意脚本注入到网页中&#xff0c;从而实现…

基于8086密码锁可修改仿真

**单片机设计介绍&#xff0c;基于8086密码锁可修改仿真 文章目录 一 概要二、功能设计三、 软件设计原理图 五、 程序六、 文章目录 一 概要 基于8086的密码锁可修改仿真设计是一个结合了微处理器控制、密码管理和仿真技术的综合性项目。通过此设计&#xff0c;用户可以设定和…

海外媒体宣发技巧解析从而提升宣发效果

在当今全球化的媒体环境下&#xff0c;海外媒体宣发是企业和品牌推广的重要手段。然而&#xff0c;要在海外市场取得成功&#xff0c;一味地复制国内的宣发策略是行不通的。要想提升宣发效果&#xff0c;就必须了解并掌握一些海外媒体宣发的技巧。世媒讯一家从事海内外媒体的推…

JSON与AJAX:网页交互的利器

在现代Web开发中&#xff0c;JSON&#xff08;JavaScript Object Notation&#xff09;和AJAX&#xff08;Asynchronous JavaScript and XML&#xff09;是两项不可或缺的技术。它们共同为网页提供了动态、实时的数据交互能力&#xff0c;为用户带来了更加流畅和丰富的体验。本…

git配置SSH 密钥

git配置SSH 密钥 1.window配置ssh1.安装ssh2.安装 Git&#xff08;安装教程参见安装Git&#xff09;并保证版本大于 1.9![在这里插入图片描述](https://img-blog.csdnimg.cn/direct/e59f4e16b83c45649f1d9d7bd6bf92c0.png)3.SSH 尽量保持最新&#xff0c;6.5之前的版本由于使用…

用ChatGPT出题,完全做不完

最近小朋友正在学习加减法&#xff0c;正好利用ChatGPT来生成加减法练习题&#xff0c;小朋友表示够了&#xff0c;够了&#xff0c;完全做不完。本文将给大家介绍如何利用ChatGPT来生成练习题。 尚未获得ChatGPT的用户&#xff0c;请移步&#xff1a;五分钟开通GPT4.0。 角色…

Hbase常用命令选择题

题目&#xff1a;在HBase Shell中&#xff0c;哪个命令用于列出所有表&#xff1f; A. list B. show C. display D. tables 答案&#xff1a;A 解析&#xff1a;在HBase Shell中&#xff0c;list和tables命令都可以用来列出所有的表。但在较新版本的HBase中&#xff0c;推荐使用…

C++20之Concept

C20之Concept&#xff08;概念部分&#xff0c;之一&#xff09;_c concept-CSDN博客 C20之Concpet&#xff08;概念部分&#xff0c;之二&#xff09;_c concept-CSDN博客

未来AI技术的创业机遇:探索科技创新的前沿领域

在当今科技创新的浪潮中&#xff0c;人工智能&#xff08;AI&#xff09;技术已成为最引人注目的前沿领域之一。AI技术不仅在科学研究中占据着举足轻重的地位&#xff0c;而且在商业应用中也展现出了巨大的潜力&#xff0c;为创业者提供了前所未有的机会和挑战。本文将探讨随着…

Cadence HDL原理图创建时多个VCC或GND处理方法

1.先new一个 2. 下面的Global pin 的name处不要直接使用GND&#xff0c;不然后期画图容易混淆。 数字地使用VSS&#xff1b;模拟地使用VEE等 3. 之后继续按照普通原理图进行绘制即可。 原理图封装绘制 4. 最后在原理图中要对该网络进行说明&#xff01;&#xff01;&#…

判断点在多边形内的算法

在计算几何中&#xff0c;判定点是否在多边形内&#xff0c;是个非常有趣的问题。通常有两种方法&#xff1a; 一、Crossing Number&#xff08;交叉数&#xff09; 它计算从点P开始的射线穿过多边形边界的次数。当“交叉数”是偶数时&#xff0c;点在外面;当它是奇数时&…

【蓝桥杯第十三届省赛B组】(详解)

九进制转十进制 #include <iostream> #include<math.h> using namespace std; int main() {cout << 2*pow(9,3)0*pow(9,2)2*pow(9,1)2*pow(9,0) << endl;return 0; }顺子日期 #include <iostream> using namespace std; int main() {// 请在此…

为什么很多程序员都建议使用 Linux?

一个好的操作系统应该是有什么问题普通用户搞不定&#xff0c;但程序员肯定搞得定。Linux就是这样的操作系统。 Windows嘛&#xff0c;出问题了普通用户搞不定&#xff0c;程序员也搞不定&#xff0c;某些运维能搞定&#xff0c;某些只有m$才搞定。在windows面前程序员都得向m…

程序员35岁会失业吗?会!!!!

程序员35岁会失业吗&#xff1f; 35岁被认为是程序员职业生涯的分水岭&#xff0c;许多程序员开始担忧自己的职业发展是否会受到年龄的限制。有人担心随着年龄的增长&#xff0c;技术更新换代的速度会使得资深程序员难以跟上&#xff1b;而另一些人则认为&#xff0c;丰富的经…

【二叉树】Leetcode 114. 二叉树展开为链表【中等】

二叉树展开为链表 给你二叉树的根结点 root &#xff0c;请你将它展开为一个单链表&#xff1a; 展开后的单链表应该同样使用 TreeNode &#xff0c;其中 right 子指针指向链表中下一个结点&#xff0c;而左子指针始终为 null 。展开后的单链表应该与二叉树 先序遍历 顺序相同…