备战秋招60天算法挑战,Day29

news2025/2/23 17:01:29

题目链接: https://leetcode.cn/problems/decode-ways/

视频题解: https://www.bilibili.com/video/BV181YKeGE3E/

LeetCode 91. 解码方法

题目描述

一条包含字母 A-Z 的消息通过以下映射进行了 编码

'A' -> "1"
'B' -> "2"
...
'Z' -> "26"

解码 已编码的消息,所有数字必须基于上述映射的方法,反向映射回字母(可能有多种方法)。例如,"11106" 可以映射为:

  • "AAJF" ,将消息分组为 (1 1 10 6)
  • "KJF" ,将消息分组为 (11 10 6)

注意,消息不能分组为 (1 11 06) ,因为 "06" 不能映射为 "F" ,这是由于 "6""06" 在映射中并不等价。

给你一个只含数字的 非空 字符串 s ,请计算并返回 解码 方法的 总数

题目数据保证答案肯定是一个 32 位 的整数。

举个例子:

输入: s = "12"
输出: 2
解释: 它可以解码为 "AB"(1 2)或者 "L"(12)。

视频题解

解码方法

思路来源

思路来源

知识回顾

动态规划是一种通过将原问题分解为子问题来求解复杂问题的算法思想。它通常用于求解最优化问题,例如最长公共子序列、背包问题等。动态规划的核心思想是将原问题分解为若干个子问题,通过求解子问题的最优解推导出原问题的最优解。可以通过两点来判断一个问题能不能通过动态规划来解,一是该问题是否存在递归结构,二是对应的子问题能否记忆化。动态规划可以通过带备忘录的自上而下的递归自下而上的迭代来分别实现。由于递归需要用到栈来实现,一些语言对递归的深度是有限制的,所以自下而上的迭代是动态规划的最佳实现方式

思路解析

计算s[i,n)区间解码数量时,可以把问题拆解成独立的子问题

  1. 如果s[i]'1'~'9'范围内,可以被单独解码,这个时候被解码的数量其实就是子问题[i+1,n)区间解码数量。
  2. 如果s[i]s[i+1]"10"~"26"范围内,可以被组合解码,这个时候被解码的数量其实就是子问题[i+2,n)区间解码数量。
  3. 如果12中的条件都满足,那么被解码的数量就是子问题[i+1,n)区间和子问题[i+2,n)区间解码数量之和。

上述过程的子问题是可以记忆化的,我们增加一个备忘录来保存子问题的解,推导原问题时避免重复计算。这就满足了使用动态规划的条件:存在递归结构子问题可以记忆化。所以本题可以用动态规划来解。动态规划可以通过带备忘录的自上而下的递归自下而上的迭代来分别实现。

方法1 自上而下的递归+备忘录

递归的关键在于划分子问题确定跳出递归的条件

递归是一种自上而下的推导方式,这里跳出递归条件就是子问题区间为空备忘录中已经保存了子问题的解

C++代码

class Solution {
public:
    int numDecodings(string s) {
        map<int, int> count;
        count[s.length()] = 1;
        return dfs(s, count, 0);
    }

    int dfs(string& s, map<int, int>& count, int i) {
        //跳出递归条件
        if (count.find(i) != count.end()) {
            return count[i];
        }
        //跳出递归条件
        if (s[i] == '0') {
            return 0;
        }
        //子问题处理
        int res = dfs(s, count, i + 1);
        if (i + 1 < s.length() && (s[i] == '1' || (s[i] == '2'&& s[i + 1] >= '0' && s[i + 1] <= '6'))) {
            //子问题处理
            res += dfs(s, count, i + 2);
        }
        //更新备忘录
        count[i] = res;
        return res;
    }
};

java代码

class Solution {
    public int numDecodings(String s) {
        Map<Integer, Integer> count = new HashMap<>();
        count.put(s.length(), 1);
        return dfs(s, count, 0);
    }
    public int dfs(String s, Map<Integer, Integer> count, int i) {
        // 跳出递归条件
        if (count.containsKey(i)) {
            return count.get(i);
        }
        // 跳出递归条件
        if (s.charAt(i) == '0') {
            return 0;
        }
        // 子问题处理
        int res = dfs(s, count, i + 1);
        if (i + 1 < s.length() && (s.charAt(i) == '1' || (s.charAt(i) == '2' && s.charAt(i + 1) >= '0' && s.charAt(i + 1) <= '6'))) {
            // 子问题处理
            res += dfs(s, count, i + 2);
        }
        // 更新备忘录
        count.put(i, res);
        return res;
    }

}

python代码

class Solution:
    def numDecodings(self, s: str) -> int:
        count = {len(s): 1}
        return self.dfs(s, count, 0)

    def dfs(self, s, count, i):
        # 跳出递归条件
        if i in count:
            return count[i]
        # 跳出递归条件
        if s[i] == '0':
            return 0
        # 子问题处理
        res = self.dfs(s, count, i + 1)
        if i + 1 < len(s) and (s[i] == '1' or (s[i] == '2' and s[i + 1] >= '0' and s[i + 1] <= '6')):
            # 子问题处理
            res += self.dfs(s, count, i + 2)
        # 更新备忘录
        count[i] = res
        return res

复杂度分析

时间复杂度: O(n)ns的长度。

空间复杂度: O(n)ns的长度。

方法2 自下而上的迭代

实现自下而上迭代的两个关键步骤:状态转移公式推导边界情况处理

首先定义dp[i]si字符,即区间[0,i)上解码方法的总数。

由于迭代是自下而上的,在我们求dp[i]时,其实子问题dp[i-1]dp[i-2]已经被推导出来了。

因为一个字符被编码后其范围在"1"~"26"之间,我们需要对s[i-1]s[i-2]分情况进行分析。

  1. s[i-1]被单独解码,如果s[i-1]'1'~'9'范围内,可以被单独解码,这个时候被解码的数量dp[i]等于dp[i-1]
  2. s[i-2]s[i-1]一起被解码,如果s[i-2]s[i-1]"10"~"26"范围内,可以被组合解码,这个时候被解码的数量dp[i]等于dp[i-2]
  3. 如果12中的条件都满足,那么被解码的数量dp[i]等于dp[i-1] + dp[i-2]

由上面的分析可以知道状态转移公式如下:

对于边界条件 dp[0] = 1,因为空字符串也可以被解码为空字符串。

C++代码

class Solution {
public:
    int numDecodings(string s) {
        int s_len = s.length();
        vector<int> dp(s_len + 1, 0);
        //边界条件处理
        dp[0] = 1;
        for(int i = 1; i <= s_len; ++i) {
            //状态转移公式
            if (s[i - 1] != '0') dp[i] = dp[i - 1];
            if (i - 1 > 0 && ((s[i - 2] == '1') || (s[i - 2] == '2' && s[i - 1] >= '0' && s[i - 1] <= '6'))) {
                //状态转移公式
                dp[i] += dp[i - 2];
            }
        }
        return dp[s_len];
    }

};

java代码

class Solution {
    public int numDecodings(String s) {
        int sLen = s.length();
        int[] dp = new int[sLen + 1];
        // 边界条件处理
        dp[0] = 1;
        for (int i = 1; i <= sLen; ++i) {
            // 状态转移公式
            if (s.charAt(i - 1) != '0') dp[i] = dp[i - 1];
            if (i - 1 > 0 && ((s.charAt(i - 2) == '1') || (s.charAt(i - 2) == '2' && s.charAt(i - 1) >= '0' && s.charAt(i - 1) <= '6'))) {
                // 状态转移公式
                dp[i] += dp[i - 2];
            }
        }
        return dp[sLen];

    }
}

python代码

class Solution:
    def numDecodings(self, s: str) -> int:
        s_len = len(s)
        dp = [0] * (s_len + 1)
        # 边界条件处理
        dp[0] = 1
        for i in range(1, s_len + 1):
            # 状态转移公式
            if s[i - 1] != '0':
                dp[i] = dp[i - 1]
            if i - 1 > 0 and (s[i - 2] == '1' or (s[i - 2] == '2' and '0' <= s[i - 1] <= '6')):
                # 状态转移公式
                dp[i] += dp[i - 2]
        return dp[s_len]

复杂度分析

时间复杂度: O(n)ns的长度。

空间复杂度: O(n)ns的长度。

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

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

相关文章

大力出奇迹背景下的Scaling Law能否带领我们走向AGI

Scaling Law&#xff08;尺度定律&#xff09; 在人工智能领域&#xff0c;尤其是在大模型的发展中扮演着至关重要的角色。它描述了模型性能如何随着模型规模&#xff08;如参数数量&#xff09;、数据量和计算资源的增加而提升。这一定律对于理解大模型的能力扩展和优化训练策…

CSS3文本属性详解

4.2 文本属性 想缩进段落&#xff0c;幂指数&#xff0c;标题字符增加间距&#xff0c;要用到文本属性。 最有用的CSS文本属性&#xff1a; text-indent:文本缩进letter-spacing:字符间距word-spacing:单词间距text-decoration:文本装饰&#xff0c;下划线text-align:文字对…

2024年小鹏MONA M03 P7 G3 G3i P5 G9 P7i G6 X9维修手册和电路图

汽修帮手资料库提供各大厂家车型维修手册、电路图、新车特征、车身钣金维修数据、全车拆装、扭力、发动机大修、发动机正时、保养、电路图、针脚定义、模块传感器、保险丝盒图解对照表位置等&#xff0c;并长期保持高频率资料更新&#xff01; 覆盖车型&#xff1a; 2024年小…

langchain结合searXNG实现基于搜索RAG

目录 一、背景 二、环境说明和安装 1.1 环境说明 2.2 环境安装 2.2.1 searXNG安装 三、代码实现 代码 结果输出 直接请求模型输出 四、参考 一、背景 大语言模型的出现带来了新的技术革新&#xff0c;但是大模型由于训练语料的原因&#xff0c;它的知识和当前实时热点…

白酒酿造设备大揭秘:科技与传统的结合

在白酒的酿造世界里&#xff0c;设备与工艺同样重要。它们共同构建了白酒的不同风味和品质。今天&#xff0c;就让我们一起走进豪迈白酒&#xff08;HOMANLISM&#xff09;的酿造车间&#xff0c;探索那些科技与传统相结合的酿造设备&#xff0c;感受它们如何为白酒的酿造增添魅…

Seata环境搭建

1、Seata下载&#xff1a; 1.下载地址 2.下载的版本 2、Seata参数配置参考&#xff1a; 各种seata参数官网参考 3、Seata安装部署&#xff1a; 3.1.Seata新手部署指南: 3.2.在mysql8.0数据库里面建库建表 a.建数据库&#xff1a; create database seata; use seata;b.建…

开源项目管理工具 Plane 安装和使用教程

说到项目管理工具&#xff0c;很多人脑海中第一个蹦出来的可能就是 Jira 了。没错&#xff0c;Jira 确实很强大&#xff0c;但是...它也有点太强大了&#xff0c;既复杂又昂贵&#xff0c;而且目前也不再提供私有化部署版本了。 再说说飞书&#xff0c;作为国产之光&#xff0…

电路基础 ---- 负反馈放大电路的方框图分析法

1 方框图分析法 方框图如下&#xff1a; 图中 A u o A_{uo} Auo​是一个电压输入的放大器的放大倍数&#xff0c;称为开环放大倍数。 F F F为反馈系数&#xff0c;是一个矢量&#xff0c;是指输出信号 x o x_{o} xo​的多少倍回送到放大器的输入端。 M M M为衰减系数&#x…

[pytorch] --- pytorch基础之损失函数与反向传播

1 损失函数 1.1 Loss Function的作用 每次训练神经网络的时候都会有一个目标&#xff0c;也会有一个输出。目标和输出之间的误差&#xff0c;就是用Loss Function来衡量的。所以Loss误差是越小越好的。此外&#xff0c;我们可以根据误差Loss&#xff0c;指导输出output接近目…

浏览器百科:网页存储篇-Cookie详解(一)

1.引言 在现代网页开发中&#xff0c;数据存储和管理是提升用户体验的重要环节之一。作为网页存储技术的元老&#xff0c;Cookie 自从诞生以来就扮演着不可或缺的角色。Cookie 允许网站在用户浏览器中存储小块数据&#xff0c;从而实现状态保持、用户跟踪以及个性化设置等功能…

数仓基础(六):离线与实时数仓区别和建设思路

文章目录 离线与实时数仓区别和建设思路 一、离线数仓与实时数仓区别 二、实时数仓建设思路 离线与实时数仓区别和建设思路 ​​​​​​​一、离线数仓与实时数仓区别 离线数据与实时数仓区别如下&#xff1a; 对比方面 离线数仓 实时数仓 架构选择 传统大数据架构 …

KRaft模式下的Kafka启动指南:摆脱Zookeeper依赖

一、背景介绍 多年来&#xff0c;人们一直在同时使用Apache ZooKeeper和Apache Kafka。但是自Apache Kafka 3.3发布以来&#xff0c;它就可以在没有ZooKeeper的情况下运行。同时它包含了新的命令kafka-metadata-quorum和kafka-metadata-shell?该如何安装新版kafka&#xff0c…

快手小店多店铺管理神器:甜羊浏览器

随着短视频平台的兴起&#xff0c;快手小店已经成为众多商家的重要销售渠道。然而&#xff0c;对于同时管理多个快手小店的商家来说&#xff0c;如何高效地运营这些店铺成为了一大挑战。特别是在需要同时登录和管理多个店铺账号时&#xff0c;问题尤为突出。那么&#xff0c;如…

【Python报错已解决】“ImportError: cannot import name ‘triu‘ from ‘scipy.linalg‘“?

&#x1f3ac; 鸽芷咕&#xff1a;个人主页 &#x1f525; 个人专栏: 《C干货基地》《粉丝福利》 ⛺️生活的理想&#xff0c;就是为了理想的生活! 文章目录 引言&#xff1a;一、问题描述1.1 报错示例&#xff1a;以下代码尝试从 scipy.linalg 中导入 triu 函数。1.2 报错分析…

@JsonFormat失败问题处理

JsonFormat失败问题处理 在开发中经常使用到时间格式&#xff0c;如果数据库的时间是timestamp格式的&#xff0c;则返回的格式通过带有毫秒 例如2024-08-30 14:53:58.236 这样子的格式&#xff0c;通常不是我们想要的&#xff1b; 但是我们又不想再后端写更多的代码&#xff…

公司电脑的敏感文件怎么审查?七大敏感文件管控策略,高效应对企业泄密风险!

在数字化时代&#xff0c;企业的敏感文件如同珍贵的宝藏&#xff0c;需时刻警惕潜在的风险。 古有"城门失火&#xff0c;殃及池鱼"之警&#xff0c;今有企业敏感信息泄露&#xff0c;牵一发而动全身之虞。 因此&#xff0c;如何有效审查与管理公司电脑中的敏感文件…

将.xml格式转换为YOLO所需的.txt文件格式

首先&#xff0c;原始的.xml数据集基础构成如下&#xff1a; image目录结构如下&#xff1a; label目录结构如下&#xff1a; .xml内容如下&#xff1a; 之后修改代码如下&#xff1a; import xml.etree.ElementTree as ET import os, cv2 import numpy as np from os import…

机器学习(西瓜书)第 3 章 线性模型

3.1 基本形式 例如若在西瓜 问题中学得“/好瓜⑺- 0.2 • n色泽 0.5 •/根蒂 0.3 •力敲声 1”&#xff0c;则意味着可 通过综合考虑色泽、根蒂和敲声来判断瓜好不好&#xff0c;其中根蒂最要紧&#xff0c;而敲声比 色泽更重要. 本章介绍几种经典的线性模型.我们先从回归任务…

为什么正午选她演大女主戏?看到殷桃这个片段,我全懂了

最近小编听说正午的最新力作《凡人歌》要上了&#xff0c;而且女主还是我特别喜欢的殷桃&#xff0c;赶紧马不停蹄的去追剧&#xff0c;结果狠狠爱上了殷桃的演技&#xff01; 剧里殷桃饰演的沈琳是一位家庭主妇&#xff0c;她以为她放弃了工作&#xff0c;做家庭主妇&#xff…

你还在为编程效率低下而烦恼吗?编程界的神级辅助!一键解锁高效编程模式,让你的工作效率飙升不止一倍!

哪个编程工具让你的工作效率翻倍&#xff1f; 第一章 引言 在软件开发领域&#xff0c;编程工具的重要性不言而喻。它们不仅能够加速开发过程&#xff0c;还能提高代码质量&#xff0c;从而显著提升开发人员的工作效率。随着技术的不断进步&#xff0c;越来越多的编程工具涌现…