Leetcode回溯法题解

news2025/1/22 12:54:46

第一题

17. 电话号码的字母组合

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

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

示例1:

输入:digits = "23"
输出:["ad","ae","af","bd","be","bf","cd","ce","cf"]

思路

我们可以把这道题转换成另一种更好理解的方式。想象一下,现在我们眼前有编号为“0”和“1”的两个箱子。“0”号箱子可以放入“a”,“b”,“c”三张牌,“1”号箱子可以放入“d”,“e”,“f”三张牌。问,一共有几种搭配方案?

穷举法

在这里插入图片描述
一个很简单的思路,我们可以进行两层for循环,穷举每一种可能的组合。第一层for循环遍历“0”号箱子的每一种可能,也就是从‘a’到‘c’。第二层for循环遍历“1”号箱子的每一种可能,也就是从‘d’到‘f’。

List<String> result = new ArrayList<>();
StringBuilder path = new StringBuilder<>();

for(char s1 = 'a'; s1 <= 'c'; s1++){
    path.append(s1);
    for(char s2 = 'd'; s2 <= 'f'; s2++){
        path.append(s2);
        result.add(path.toString());
    }
}

return result;

我们现在已经知道了示例1的每一位是什么,自然可以写出上面的代码。但是,实际上digits是不确定的,我们无法知道它的具体长度和每一位,那怎么知道要如何写for循环?

回溯法

一个更好的思路,是用递归函数来代替多层for循环,每一层递归就相当于一层for循环。在递归完digits最后一个元素后,结束递归。

class Solution {
    private List<String> result = new ArrayList<String>();
    private StringBuilder path = new StringBuilder();
    private String[] numString = {"", "", "abc", "def", "ghi", "jkl", "mno", "pqrs", "tuv", "wxyz"};
    
    /**
     * 返回digits能表示的字母组合
     * @param String digits,digits的每一位对应numString中的一个String
     * @return List<String> result,digits能表示的字母组合
     */
    public List<String> letterCombinations(String digits) {
        if(digits.length() == 0 || digits == null){
            return result;
        }
        // 从digits[0]开始搜索,也是首次递归
        dfs(0, digits);
        return result;
    }
    
    /**
     * 递归搜索digits的每一位
     * @param int step,step代表digits的第几位,同时也代表了递归的第几层
     * @param String digits,digits的每一位对应numString中的一个字符串num
     */
    private void dfs(int step, String digits){
        // 如果递归完digits最后一个元素,那么保存结果,结束递归
        if(step == digits.length()){
            result.add(path.toString());
            return;
        }
        // 获取digits的第step位元素
        char idx = digits.charAt(step);
        // 获取digits的第step位元素对应的字符串
        String num = numString[idx - '0'];
        // 对digits的第step位元素对应的字符串num进行“树层遍历”
        for(int i = 0; i < num.length(); i++){
            char item = num.charAt(i);
            // 放入第step位元素对应的字符
            path.append(item);
            // 进行“树枝遍历”,继续递归遍历第step + 1位元素对应的字符
            dfs(step + 1, digits);
            // 清空第step位元素对应的字符
            path.deleteCharAt(path.length() - 1);
        }
        // 如果对这一层完成了“树层遍历”,那么返回上一层
        return;
    }
}

结合示例1来看。在递归的第0层,首先遍历digits[0],‘2’。'2’对应的num为"abc",接下来就对num进行“树层遍历”。在第0层递归的“树层遍历”中,第一次选择将‘a’放入“0”号箱子中,然后进入下一层递归进行“树枝遍历”,选择放入“1”号箱子中的字符。同样的,在第1层递归的“树层遍历”中,第一次选择将‘d’放入“1”号箱子中,然后进入下一层递归进行“树枝遍历”。当到达第2层递归时,已经递归完digits最后一个元素,那么保存结果,结束递归。

在这里插入图片描述

现在,回到了第1层递归的“树层遍历”中。第一次我们选择将‘d’放入“1”号箱子中,现在我们要将‘d’从“1”号箱子中取出(path.deleteCharAt(path.length() - 1)),选择将‘e’放入“1”号箱子中。

当我们把“def”都选择过一遍之后,返回第0层递归的“树层遍历”中。第一次我们选择将‘a’放入“0”号箱子中,现在我们要将‘a’从“0”号箱子中取出(path.deleteCharAt(path.length() - 1)),选择将‘b’放入“0”号箱子中。

回溯法通过递归函数,可以实现多次for循环,遍历所有可能的结果。

总结

最后,我们可以总结出回溯法使用递归函数实现多层循环的代码模版。

void dfs(){
    if(达到了递归条件){
        保存结果
        返回
    }
    
    for(进行“树层循环”){
        添加元素
        dfs(进行“树枝循环”)
        移除元素
    }
}

参考:
代码随想录
啊哈!算法

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

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

相关文章

Linux yum 使用手册,以及内网源搭建

Linux yum 内网源搭建 序 在 Linux 中&#xff0c;我们经常安装各个开源网站编写的代码、软件&#xff0c;在安装的时候各个软件之间有各种依赖关系&#xff0c;还可能出现版本问题&#xff0c;比如 Centos7 支持的软件&#xff0c; Centos6 就未必支持。如果是 Java 开发应该…

ArcGIS基础实验操作100例--实验73创建闭合线内部缓冲区

本实验专栏参考自汤国安教授《地理信息系统基础实验操作100例》一书 实验平台&#xff1a;ArcGIS 10.6 实验数据&#xff1a;请访问实验1&#xff08;传送门&#xff09; 高级编辑篇--实验73 创建闭合线内部缓冲区 目录 一、实验背景 二、实验数据 三、实验步骤 &#xff0…

K8S ReplicaSet 原理 示例 HPA扩容

K8S ReplicaSet 基本使用 K8S ReplicaSet 对象的作用是在任意时间点保持一组稳定的副本Pod运行&#xff0c;因此&#xff0c;它通常用于保证指定数量的相同Pod的可用性。乍一看&#xff0c; ReplicaSet 对象的定义跟 Replication Controller 并没有什么区别&#xff0c;都是维…

AI检测人员工衣工服着装不规范识别系统 yolo

AI检测人员工衣工服着装不规范识别系统基于opencvyolo网络深度学习模型对现场画面中人员着装穿戴实时监测分析。我们使用YOLO(你只看一次)算法进行对象检测。YOLO是一个聪明的卷积神经网络(CNN)&#xff0c;用于实时进行目标检测。该算法将单个神经网络应用于完整的图像&#x…

Vivado综合属性之SRL_STYLE

本文介绍综合属性SRL_STYLE取register、srl、srl_reg、reg_srl、reg_srl_reg和block中的值时&#xff0c;对Schematic的影响。 SRL_STYLE用于指导Vivado将SRL&#xff08;移位寄存器&#xff09;映射为何种形式。 目录 默认值 测试代码 原理图 SRL_STYLE配置为register …

【JavaSE】String类

目录 前言&#xff1a; 1.1、了解字符串构造方法 1.2、求字符串长度&#xff08;xxx.length()&#xff09; 1.3、isEmpty()方法 1.4、String对象的比较 1.4.1、通过&#xff08;str1 str2&#xff09;来比较&#xff0c;这样比较的是两个引用当中的地址 1.4.2、 boolea…

【ONE·C++ || vector (一)】

总言 学习笔记&#xff0c;慢慢补充。 文章目录总言1、整体介绍&#xff1a;2、常用各种接口介绍2.1、vector的基本结构&#xff1a;构造、析构、赋值2.1.1、总体情况预览2.1.2、各项函数使用演示2.2、vector增删查改相关2.2.1、增删查改总览2.2.2、如何在vector中插入、删除、…

Kotlin之使用协程编写高效的并发程序

文章目录1.协程的基本用法2.更多的作用域构建器3.使用协程简化回调的写法协程属于Kotlin中非常有特色的一项技术&#xff0c;因为大部分编程语言中是没有协程这个概念的。那么什么是协程呢&#xff1f;它其实和线程有点相似&#xff0c;可以简单地将它理解成一种轻量级的线程。…

Linux学习入门

1、Linux简介 操作系统分类&#xff1a;桌面操作系统、、服务器操作系统、移动端操作系统、嵌入式操作系统桌面操作系统主要针对个人电脑&#xff0c;Linux在桌面操作系统的应用主要有国产操作系统&#xff0c;Ubuntu。服务器操作系统有windows和linux以及苹果&#xff0c;主流…

微信小程序是如何实现快速编译的?

过往中小企业或技术团队开发一个 App 的时间成本和人力成本居高难下&#xff0c;但是随着微信上线小程序&#xff0c;更像是为这部分群体打开了一扇天窗&#xff0c;此后小程序呈现出井喷式发展的状态&#xff0c;不仅微信&#xff0c;支付宝、百度、抖音等超级 App 都跟上步伐…

线程进阶

常见的锁策略乐观锁 vs 悲观锁乐观锁&#xff1a;预测锁竞争不是很激烈悲观锁&#xff1a;预测锁竞争会很激烈轻量级锁 vs 重量级锁轻量级锁加锁解锁开销比较小&#xff0c;效率更高重量级锁加锁解锁开销比较大&#xff0c;效率更低多数情况下&#xff0c;乐观锁&#xff0c;也…

在CSDN年收入竟达五位数?----大学生技术自媒体成长之路

前言&#xff1a; Hello大家好&#xff0c;我是Dream。 还有不到两周就要过年了&#xff0c;自己也马上迈入了21岁&#xff0c;感慨时间飞快&#xff0c;从19岁开始入驻C站&#xff0c;到现在也已经整整两年了&#xff0c;把自己最好的两年青春时光留在了CSDN&#xff0c;超百万…

定义输出格式的使用-printf()函数

目录&#x1f4d6;printf()函数简介格式化规定符格式控制特殊规定字符示例printf()函数简介 printf()函数是格式化输出函数, 一般用于向标准输出设备按规定格式输出信息。 printf()函数的调用格式为:printf("<格式化字符串>", <参量表>);这里看输出很简…

Lua入门学习

一、初识Lua脚本 Lua 是一种轻量小巧的脚本语言&#xff0c;用标准C语言编写并以源代码形式开放&#xff0c; 其设计目的是为了嵌入应用程序中&#xff0c;从而为应用程序提供灵活的扩展和定制功能。官网&#xff1a;https://www.lua.org/ 1、HelloWorld CentOS7默认已经安装…

什么是docker

文章目录简介Docker 架构特性局限Docker 是一个开源的应用容器引擎&#xff0c;让开发者可以打包他们的应用以及依赖包到一个可移植的镜像中&#xff0c;然后发布到任何流行的 Linux或Windows操作系统的机器上&#xff0c;也可以实现虚拟化。容器是完全使用沙箱机制&#xff0c…

〖产品思维训练白宝书 - 产品思维认知篇⑨〗- 像 产品经理 一样去思考解决问题

大家好&#xff0c;我是 哈士奇 &#xff0c;一位工作了十年的"技术混子"&#xff0c; 致力于为开发者赋能的UP主, 目前正在运营着 TFS_CLUB社区。 &#x1f4ac; 人生格言&#xff1a;优于别人,并不高贵,真正的高贵应该是优于过去的自己。&#x1f4ac; &#x1f4e…

数据结构:算法的初步认识

算法是解决特定问题求解步骤的描述&#xff0c;在计算机中表现为指令的有限序列&#xff0c;并且每条指令表示一个或多个操作。 什么是算法 要求你写一个求 123…100 结果的程序&#xff0c;你应该怎么写呢? 大多数人会马上写出下面的C语言代码(或者其他语言的代码): int a,…

seata的AT模式

seata 分布式事务解决方案 官网 &#xff1a; seata.io 事务模式&#xff1a; 名词 TC &#xff1a; transaction coordinator 事务协调者 维护全局事务 和 分支事务的状态&#xff0c;驱动全局事务提交或者回滚TM &#xff1a; transaction manager 事务管理器 定义全局事…

(考研湖科大教书匠计算机网络)第一章概述-第三节:计算机网络的定义、功能分类

文章目录一&#xff1a;计算机网络的定义&#xff08;1&#xff09;最简单定义&#xff08;2&#xff09;较好定义二&#xff1a;计算机网络功能三&#xff1a;计算机网络的分类&#xff08;1&#xff09;按照“覆盖范围”分类&#xff08;2&#xff09;按照“使用者”分类&…

【Linux学习】进程控制

&#x1f431;作者&#xff1a;一只大喵咪1201 &#x1f431;专栏&#xff1a;《Linux学习》 &#x1f525;格言&#xff1a;你只管努力&#xff0c;剩下的交给时间&#xff01; 在前面&#xff0c;我们学习了进程的相关概念&#xff0c;在这里本喵会给大家介绍如何控制进程。…