动态规划——斐波那契数列模型:91.解码方法

news2024/9/23 11:22:42

文章目录

  • 题目描述
  • 算法原理
    • 1.状态表示
    • 2.状态转移方程
    • 3.初始化
      • ⽅法⼀(直接初始化)
      • ⽅法⼆(添加辅助位置初始化)
    • 4.填表顺序
    • 5.返回值
  • 代码实现
    • C++
    • 优化
    • Java
    • 优化

题目描述

题目链接:91.解码方法
在这里插入图片描述
在这里插入图片描述

算法原理

类似于斐波那契数列~

1.状态表示

根据以往的经验,对于⼤多数线性 dp ,我们经验上都是以某个位置结束或者开始做⽂章,这⾥我们继续尝试⽤ i 位置为结尾结合题⽬要求来定义状态表⽰。
dp[i] 表⽰:字符串中 [0,i] 区间上,⼀共有多少种编码⽅法在这里插入图片描述

2.状态转移方程

定义好状态表⽰,我们就可以分析 i 位置的 dp 值,如何由前面或者后面的信息推导出来。接下来根据最近一步,划分问题。
关于 i 位置的编码状况,我们可以分为下⾯两种情况:

  • 让 i 位置上的数单独解码成⼀个字⺟;
  • 让 i 位置上的数与 i - 1 位置上的数结合,解码成⼀个字⺟。

下⾯我们就上⾯的两种解码情况,继续分析。
让 i 位置上的数单独解码成⼀个字⺟,就存在解码成功解码失败两种情况:

  • 解码成功:当 i 位置上的数在 [1, 9] 之间的时候,说明 i 位置上的数是可以单独解码的,那么此时 [0, i] 区间上的解码⽅法应该等于 [0, i - 1] 区间上的解码⽅法。因为 [0, i - 1] 区间上的所有解码结果,后⾯填上⼀个 i 位置解码后的字⺟就可以了。此时 dp[i] = dp[i - 1] ;
  • 解码失败:当 i 位置上的数是 0 的时候,说明 i 位置上的数是不能单独解码的,那么此时 [0, i] 区间上不存在解码⽅法。因为 i 位置如果单独参与解码,但是解码失败了,那么前⾯做的努⼒就全部⽩费了。此时 dp[i] = 0 。

让 i 位置上的数与 i - 1 位置上的数结合在⼀起,解码成⼀个字⺟,也存在解码成功解码失败两种情况:

  • 解码成功:当结合的数在 [10, 26] 之间的时候,说明 [i - 1, i] 两个位置是可以解码成功的,那么此时 [0,i] 区间上的解码⽅法应该等于 [0, i - 2 ] 区间上的解码⽅法,原因同上。此时 dp[i] = dp[i - 2] ;

  • 解码失败:当结合的数在 [0, 9] 和 [27 , 99] 之间的时候,说明两个位置结合后解码失败(这⾥⼀定要注意 00 01 02 03 04 … 这⼏种情况),那么此时 [0, i] 区间上的解码⽅法就不存在了,原因依旧同上。此时 dp[i] = 0 。

在这里插入图片描述
综上所述: dp[i]( dp[i] 默认初始化为 0 )最终的结果应该是上⾯四种情况下,解码成功的两种的累加和(因为我们关⼼的是解码⽅法,既然解码失败,就不⽤加⼊到最终结果中去),因此可以得到状态转移⽅程

//当s[i]上的数在[1, 9]区间上时:dp[i] += dp[i - 1];
//当s[i - 1]与s[i]上的数结合后,在[10, 26]之间的时候:dp[i] += dp[i - 2];
//如果上述两个判断都不成⽴,说明没有解码⽅法,dp[i]就是默认值 0

3.初始化

⽅法⼀(直接初始化)

由于可能要⽤到 i - 1 以及 i - 2 位置上的 dp 值,因此要先初始化前两个位置
初始化 dp[0] :

  • 当 s[0] == ‘0’ 时,没有编码⽅法,结果 dp[0] = 0;
  • 当 s[0] != ‘0’ 时,能编码成功, dp[0] = 1;

初始化 dp[1] :

  • 当 s[1] 在 [1,9] 之间时,能单独编码,此时 dp[1] += dp[0] (原因同上,dp[1] 默认为 0);
  • 当 s[0] 与 s[1] 结合后的数在 [10, 26] 之间时,说明在前两个字符中,⼜有⼀种编码⽅式,此时 dp[1] += 1;

⽅法⼆(添加辅助位置初始化)

可以在最前⾯加上⼀个辅助结点,帮助我们初始化。使⽤这种技巧要注意两个点:

  • 辅助结点⾥⾯的值要保证后续填表是正确的;
  • 下标的映射关系;

4.填表顺序

毫无疑问是从左往右

5.返回值

应该返回 dp[n - 1] 的值,表⽰在 [0, n - 1] 区间上的编码⽅法。

代码实现

C++

class Solution {
public:
    int numDecodings(string s) {
        //1.创建dp表
        int n = s.size();
        vector<int> dp(n);
        //2.初始化
        dp[0] = s[0] != '0';//字符串s中只含数字
        if(n == 1)return dp[0];//处理边界情况

        int t = (s[0] - '0') * 10 + (s[1] - '0');//前两个位置所表示的数
        if(t >= 10 && t <= 26)dp[1]++;//去除前导0的情况
        if(s[0] != '0' && s[1] != '0')dp[1]++;
        if(n == 2)return dp[1];

        //3.填表
        for(int i = 2;i < n;++i){
            if(s[i] != '0')dp[i] += dp[i - 1];//处理单独编码的情况
            int tmp = (s[i - 1] - '0') * 10 + (s[i] - '0');//第二种情况所对应的数
            if(tmp >= 10 && tmp <= 26)dp[i] += dp[i - 2];
        }

        //4.返回值
        return dp[n - 1];
    }
};

优化

使⽤添加辅助结点的⽅式初始化:

class Solution {
public:
    int numDecodings(string s) {
        // 优化
        int n = s.size();
        vector<int> dp(n + 1);
        dp[0] = 1; // 保证后续填表是正确的
        dp[1] = s[0] != '0';
        // 填表
        for (int i = 2; i <= n; i++) {
            // 处理单独编码
            if (s[i - 1] != '0')
                dp[i] += dp[i - 1];
            // 如果和前⾯的⼀个数联合起来编码
            int t = (s[i - 2] - '0') * 10 + s[i - 1] - '0';
            if (t >= 10 && t <= 26)
                dp[i] += dp[i - 2];
        }
        return dp[n];
    }
};

Java

class Solution {
    public int numDecodings(String ss) {
        // 1. 创建 dp 表
        // 2. 初始化
        // 3. 填表
        // 4. 返回值
        int n = ss.length();
        char[] s = ss.toCharArray();
        int[] dp = new int[n];
        if (s[0] != '0')
            dp[0] = 1; // 初始化第⼀个位置
        if (n == 1)
            return dp[0]; // 处理边界情况
        // 初始化第⼆个位置
        if (s[1] != '0' && s[0] != '0')
            dp[1] += 1;
        int t = (s[0] - '0') * 10 + s[1] - '0';
        if (t >= 10 && t <= 26)
            dp[1] += 1;
        for (int i = 2; i < n; i++) {
            // 先处理第⼀种情况
            if (s[i] != '0')
                dp[i] += dp[i - 1];
            // 处理第⼆种情况
            int tt = (s[i - 1] - '0') * 10 + s[i] - '0';
            if (tt >= 10 && tt <= 26)
                dp[i] += dp[i - 2];
        }
        return dp[n - 1];
    }
}

优化

class Solution {
    public int numDecodings(String ss) {
        // 1. 创建 dp 表
        // 2. 初始化
        // 3. 填表
        // 4. 返回值
        int n = ss.length();
        char[] s = ss.toCharArray();
        int[] dp = new int[n + 1];
        dp[0] = 1; // 保证后续填表是正确的
        if (s[1 - 1] != '0')
            dp[1] = 1;
        for (int i = 2; i <= n; i++) {
            // 先处理第⼀种情况
            if (s[i - 1] != '0')
                dp[i] += dp[i - 1];
            // 处理第⼆种情况
            int tt = (s[i - 2] - '0') * 10 + s[i - 1] - '0';
            if (tt >= 10 && tt <= 26)
                dp[i] += dp[i - 2];
        }
        return dp[n];
    }
}

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

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

相关文章

Elasticsearch初步认识

Elasticsearch初步认识 ES概述基本概念正向索引和倒排索引IK分词器ik_smart最少切分ik_max_word为最细粒度划分 ES索引库基本操作对索引库操作对文档操作 ES概述 Elasticsearch&#xff0c;简称为 ES&#xff0c;是一款非常强大的开源的高扩展的分布式全文检索引擎&#xff0c…

Linux基础之makefile/make

目录 一、背景 二、makefile和make的讲解 2.1 使用方法 2.2 伪目标文件 2.3 文件的属性以及属性的更新 2.4 makefile的自动推导 一、背景 这里会提及为什么要使用makefile和make&#xff0c;以及他们是什么和作用。 会不会写makefile&#xff0c;从一个侧面说明了一个人是…

JS基础:输出信息的5种方式详解

你好&#xff0c;我是云桃桃。 一个希望帮助更多朋友快速入门 WEB 前端的程序媛。 云桃桃-大专生&#xff0c;一枚程序媛&#xff0c;感谢关注。回复 “前端基础题”&#xff0c;可免费获得前端基础 100 题汇总&#xff0c;回复 “前端基础路线”&#xff0c;可获取完整web基础…

基于LLama3、Langchain,Chroma 构建RAG

概要&#xff1a; 使用Llama3 Langchain和ChromaDB创建一个检索增强生成&#xff08;RAG&#xff09;系统。这将允许我们询问有关我们的文档&#xff08;未包含在训练数据中&#xff09;的问题&#xff0c;而无需对大型语言模型&#xff08;LLM&#xff09;进行微调。在使用RA…

【企业动态】东胜物联正式加入EnOcean联盟,携手为智慧楼宇及能源管理提供更稳定的硬件解决方案

2024年4月&#xff0c;东胜物联&#xff08;Dusun&#xff09;宣布正式加入EnOcean联盟。EnOcean联盟是一个由来自建筑行业的400多家公司组成的全球性组织。它以EnOcean无线标准&#xff08;ISO/IEC 14543-3-10/11&#xff09;为基础&#xff0c;为可持续建筑自动化建立了创新的…

短剧APP开发:百亿短剧市场规模下的收益密码

短剧进入到大众的视野中&#xff0c;成为影视新行业&#xff0c;成为了中老年人茶余饭后的休闲方式&#xff0c;也成为了年轻人的“电子榨菜”。短剧时长短、节奏快&#xff0c;观众可以在短时间内看完一部剧&#xff0c;波澜起伏的剧情能够推动短剧的剧情&#xff0c;吸引观众…

【MRI重建】基于L+S方法的加速动态成像(MATLAB)

关于 L+S 模型很自然地可以表示动态 MRI 数据。重建欠采样数据需要 k−t 空间(采集)与 L 的奇异向量和 S 的稀疏域之间的不相干性。 L 和 S 之间的不相干性是背景和动态分量稳健分离所必需的。多线圈 L+S 重建是使用凸优化方法制定的,其中核范数用于强制 L 中的低秩,而 l1 …

58行代码把Llama 3扩展到100万上下文,任何微调版都适用 | 最新快讯

量子位公众号 QbitAI 堂堂开源之王 Llama 3&#xff0c;原版上下文窗口居然只有……8k&#xff0c;让到嘴边的一句“真香”又咽回去了。 在 32k 起步&#xff0c;100k 寻常的今天&#xff0c;这是故意要给开源社区留做贡献的空间吗&#xff1f; 开源社区当然不会放过这个机会&a…

[JUCE库]关于JUCE如何生成动态链接库 juce-7.0.1-windows

前言 当我们在使用JUCE库的时候&#xff0c;可能会需要使用到静态链接的方式&#xff0c;还好的一点是JUCE本身提供了CMake编译&#xff0c;也提供了单独的sln编译。 本文章仅针对juce-7.0.1-windows&#xff0c;由于不同版本之间差异较大&#xff0c;可能不能通用&#xff0…

Codeforces Round 943 (Div. 3) A~E

A. Maximize? Problem - A - Codeforces 给定x求出使这个式子最大的y&#xff1a; 不用想复杂直接循环枚举即可。 #include<bits/stdc.h> using lllong long; ll n,m; void solve() {int x;std::cin>>x;ll ans0,y;for(int i1;i<x;i){if(std::__gcd(i,x)i>a…

鸿蒙内核源码分析(信号量篇) | 谁在负责解决任务的同步

基本概念 信号量&#xff08;Semaphore&#xff09; 是一种实现任务间通信的机制&#xff0c;可以实现任务间同步或共享资源的互斥访问。 一个信号量的数据结构中&#xff0c;通常有一个计数值&#xff0c;用于对有效资源数的计数&#xff0c;表示剩下的可被使用的共享资源数…

linux 调试-kdb 调试内核-1

目标&#xff1a;打印bcm2835_spi_transfer_one 是如何从用户空间开始调用的 1. kernel 配置 KDB配置选项 添加 spi 控制器驱动 和 spi 设备驱动 2. 调试流程 调试内核-系统启动之后 1. 开发板进入kdb,等待pc 连接 rootraspberrypi:~# echo "ttyS0,115200"…

抖音小店如何快速出单?内行人闭口不提的诀窍,一篇全曝光!

哈喽~我是电商月月 新手做抖店不成功&#xff0c;最大的问题就是不懂技巧&#xff0c;不懂规则&#xff0c;不懂玩法&#xff0c;你基础事项&#xff0c;思维方向都没选好&#xff0c;再怎么努力也别想出单 看下去&#xff0c;新手在开店后不要着急选品&#xff0c;先把这些问…

数据结构复习指导之树的基本概念

文章目录 树与二叉树 考纲内容 复习提示 前言 1.树的基本概念 1.1树的定义 1.2基本术语 1.3树的性质 树与二叉树 考纲内容 &#xff08;一&#xff09;树的基本概念 &#xff08;二&#xff09;二叉树 二叉树的定义及其主要特征&#xff1b;二叉树的顺序存…

22 Debian如何配置Apache2(2)虚拟主机

作者&#xff1a;网络傅老师 特别提示&#xff1a;未经作者允许&#xff0c;不得转载任何内容。违者必究&#xff01; Debian如何配置Apache2&#xff08;2&#xff09;虚拟主机 《傅老师Debian小知识库系列之22》——原创 前言 傅老师Debian小知识库特点&#xff1a; 1、最…

文件加密软件排行榜前四名(2024年4大好用的加密软件推荐)

说到文件加密&#xff0c;想必大家都很熟悉&#xff0c;文件加密已经普遍应用&#xff0c;文件加密是一种重要的安全措施&#xff0c;可以确保数据的机密性、完整性和可用性&#xff0c;降低因数据泄露或丢失带来的风险 。 下面小编给大家分享几款常用的加密软件&#xff0c;…

【redis】Redis数据类型(五)ZSet类型

目录 类型介绍特点补充 使用场景 Zset类型数据结构ziplist&#xff1a;压缩列表&#xff08;参考之前的文章&#xff09;skiplist&#xff1a;跳表解析 面试题&#xff1a;MySQL索引为什么用B树而不用跳表区别总结 常用命令ZADD示例 ZREM示例 ZCARD示例 ZCOUNT示例 ZSCORE示例 …

spring高级篇(九)

boot的执行流程分为构造SpringApplication对象、调用run方法两部分 1、Spring Boot 执行流程-构造 通常我们会在SpringBoot的主启动类中写以下的代码&#xff1a; 参数一是当前类的字节码&#xff0c;参数二是main的args参数。 public class StartApplication {public static…

【微信小程序开发】微信小程序注册,配置开发者工具

准备工作 微信小程序小程序开发流程 开发过程注册小程序开发者工具开发界面介绍 微信小程序 一种新的开发能力&#xff0c;可以在微信内被便捷的获取和传播&#xff0c;具有出色的用户体验 地址&#xff1a;https://mp.weixin.qq.com/ 注册微信小程序 在进行开发之前我们应该…

从开发角度理解漏洞成因(02)

文章目录 文件上传类需求文件上传漏洞 文件下载类需求文件下载漏洞 扩展 留言板类&#xff08;XSS漏洞&#xff09;需求XSS漏洞 登录类需求cookie伪造漏洞万能密码登录 持续更新中… 文章中代码资源已上传资源&#xff0c;如需要打包好的请点击PHP开发漏洞环境&#xff08;SQL注…