【动态规划】:泰波那契模型_解码方法

news2025/1/20 3:34:19

朋友们、伙计们,我们又见面了,本专栏是关于各种算法的解析,如果看完之后对你有一定的启发,那么请留下你的三连,祝大家心想事成!

C 语 言 专 栏:C语言:从入门到精通

数据结构专栏:数据结构

个  人  主  页 :stackY、

C + + 专 栏   :C++

Linux 专 栏  :Linux

目录

1. 题目解析

2. 算法原理

2.1 状态表示

2.2 状态转移方程

2.3 初始化

2.4 填表顺序

2.5 返回值

3. 代码实现

4. 算法复杂度 

5. 优化边界情况以及初始化 

5.1 优化之后代码 


1. 题目解析

Leetcode91.解码方法:https://leetcode.cn/problems/decode-ways/description/

一条包含字母 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 位 的整数。

示例 1:

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

示例 2:

输入:s = "226"
输出:3
解释:它可以解码为 "BZ" (2 26), "VF" (22 6), 或者 "BBF" (2 2 6) 。

示例 3:

输入:s = "06"
输出:0
解释:"06" 无法映射到 "F" ,因为存在前导零("6" 和 "06" 并不等价)。

提示:

  • 1 <= s.length <= 100
  • s 只包含数字,并且可能包含前导零。

本题采用动态规划的思想,以某一位置为开始,或者以某一位置为结束,要注意的是:

例如:

06没有解码方式,因为单独的0不能解码,并且06组合起来也不能解码,06和6并不等价。

60也没有解码方式,6单独有解码方式,但是0没有,并且二者结合60也没有解码方式。 

262有两种解码方式,依次单独解码(1),26组合解码(2),但是62组合没有解码方式。

那么就表明:

一个数要能单独解码就要在'1' ~ '9' 之间

两个数组合一起能解码就要在'10' ~ '26' 之间

2. 算法原理

2.1 状态表示

根据题目要求:

要求的是总共的解码数,那么假设一共有i个数

那么我们以i位置为结尾时,所得的解码的方法就是要求的解码方法总数。

因此:dp[i] 就表示解码的方法数。

2.2 状态转移方程

根据最近的一步划分问题:

dp[i]位置的解码数就是:①s[i]单独解码数

                                       ②s[i-1]和s[i]组合起来的解码数

①如果s[i]能单独解码,那么此时的解码数就是dp[i-1]时的解码数,如果不能单独解码,那么之前的工作都作废了,总的解码数为0的。

②如果s[i-1]和s[i]组合起来能解码,那么此时的解码数就是dp[i-2]时的解码数,如果组合起来不能解码,那么就为0。

因此如果两种方式都可以解码成功:dp[i] = dp[i-1] + dp[i-2]

2.3 初始化

为了防止越界,求dp[i]就要知道dp[i-1]和dp[i-2],所以需要将dp[0]和dp[1]初始化

dp[0]就是s[0]位置的解码数,那么只有0和1两种情况,如果s[0]能单独解码,就是1,不能则是0。

dp[1]就是s[1]位置的解码数,这里存在两种情况,如果s[0]和s[1]能单独解码就算一种,如果s[0]和s[1]组合起来能解码也是一种,如果s[1]单独都不能解码就是0。

因此dp[1]的解码方法是0或1或2。

2.4 填表顺序

从左向右

2.5 返回值

dp[n-1]

3. 代码实现

class Solution 
{
public:
    int numDecodings(string s) 
    {
        int n = s.size();
        // 1. 创建dp表
        vector<int> dp(n);   

        // 2. 初始化
        dp[0] = s[0] != '0';
        // 边界情况
        if(n == 1) return dp[0];

        if(s[0] != '0' && s[1] != '0') dp[1] += 1;
        int ret = (s[0] - '0')*10 + s[1] - '0';
        if(ret >= 10 && ret <= 26) dp[1] += 1;
        
        // 3. 填表
        for(int i = 2; i<n; i++)
        {
            // 单独解码
            if(s[i] != '0') dp[i] += dp[i-1];
            int ret = (s[i-1] - '0')*10 + s[i] - '0';
            // 组合解码
            if(ret >= 10 && ret <= 26) dp[i] += dp[i-2];
        }

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

4. 算法复杂度 

时间复杂度:O(N)

空间复杂度:O(N)

5. 优化边界情况以及初始化 

通过上面的代码可以发现: 初始化部分与填表部分逻辑类似代码冗余,所以可以做以优化

我们在创建dp表时可以多创建一个空间,只需要对这个空间进初始化就可以优化繁琐的初始化过程:

既然多开了一个空间,那么就需要注意两个问题:

1. 初始化虚拟节点的值,要保证后面的填表是正确的;

2. 下标映射的关系。 

下面,我们分别来对这两个问题进行研究:

1. 初始化虚拟节点的值,要保证后面的填表是正确的

因为我们多开了一个空间,这个空间的值也就意味着后面的值正确与否,我们需要根据题目要求和状态表示来初始化这个虚拟空间的值:

状态表示:dp[i]表示解码方法数

那么这个虚拟空间的值应该被设置为1  ->  dp[0] = 1

那么为什么呢?

在计算dp[2]时,如果可以与前一个组合起来解码,那么需要加上dp[i-2],这样就正好是一种方法。

2. 下标映射的关系

由于我们多创建了一个空间,那么在填表的时候s中的下标就要统一减一。

5.1 优化之后代码 

class Solution {
public:
    int numDecodings(string s) {
        int n = s.size();
        // 多开一个空间
        vector<int> dp(n + 1);
        // 初始化
        dp[0] = 1;
        dp[1] = s[1 - 1] != '0';

        for(int i = 2; i<=n; i++)
        {
            // s的下标要对应-1
            if(s[i - 1] != '0') dp[i] += dp[i-1];
            int ret = (s[i-2] - '0')*10 + s[i - 1] - '0';
            if(ret >= 10 && ret <= 26) dp[i] += dp[i-2];
        }
        //多开一个空间所以返回第n个位置即可
        return dp[n];
    }
};

 

 

朋友们、伙计们,美好的时光总是短暂的,我们本期算法的分享就到此结束,欲知后事如何,请听下回分解~,最后看完别忘了留下你们弥足珍贵的三连喔,感谢大家的支持! 

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

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

相关文章

Codeforces Round 169 (Div. 2)C. Little Girl and Maximum Sum(差分、贪心)

文章目录 题面链接题意题解代码总结 题面 链接 C. Little Girl and Maximum Sum 题意 给q个[l,r]将所有这些区间里面的数相加和最大。 可以进行的操作是任意排列数组 题解 对出现的每个区间内的位置加上1&#xff0c;代表权值 操作完之后求一遍前缀和&#xff0c;得到每个…

通俗易懂搞定forEach和map的区别和使用

前言 在前端开发的时候&#xff0c;我们有时候需要对后端传过来的数组的进行相应的遍历处理&#xff0c;但是很多小伙伴对map和forEach两个方法的界限还是有模糊&#xff0c;本文从具体的示例来弄清楚两者的相同点和不同点 相同点 1.都是用于遍历数组的方法&#xff0c;可以…

关于氢能,什么是绿氢、蓝氢、灰氢?

今年3月,国家有关部门出台《氢能产业发展中长期规划(2021—2035年)》,明确了氢的能源属性,同时明确氢能是战略性新兴产业的重点方向是构建绿色低碳产业体系、打造产业转型升级的新增长点。一时间,氢能发展也受到了万众瞩目。我国目前已经成为世界最大的制氢国年制氢产量约…

L2-002 链表去重

一、题目 二、解题思路 结构体数组的下标表示该节点的地址&#xff0c;value 表示该节点的值&#xff0c;next 表示下一个结点的地址。result1 表示去重后的链表的节点的地址&#xff0c;result2 表示被删除的链表的节点的地址。 flag 表示节点对应的值是否出现过&#xff0c;…

【小赛1】蓝桥杯双周赛第5场(小白)思路回顾

我的成绩&#xff1a;小白(5/6) 完稿时间&#xff1a;2024-2-13 比赛地址&#xff1a;https://www.lanqiao.cn/oj-contest/newbie-5/ 相关资料&#xff1a; 1、出题人题解&#xff1a;“蓝桥杯双周赛第5次强者挑战赛/小白入门赛”出题人题解 - 知乎 (zhihu.com) 2、矩阵快速幂&…

《Java 简易速速上手小册》第9章:Java 开发工具和框架 (2024 最新版)

文章目录 9.1 Maven 和 Gradle - 构建与依赖管理的神兵利器9.1.1 基础知识9.1.2 重点案例&#xff1a;使用 Maven 构建 Spring Boot 应用9.1.3 拓展案例 1&#xff1a;使用 Gradle 构建多模块项目9.1.4 拓展案例 2&#xff1a;利用 Gradle Wrapper 确保构建的一致性 9.2 Spring…

【JavaEE Spring】Spring 原理

Spring 原理 1. Bean的作⽤域1.1 概念1.2 Bean的作⽤域 2. Bean的⽣命周期 1. Bean的作⽤域 1.1 概念 在Spring IoC&DI阶段, 我们学习了Spring是如何帮助我们管理对象的. 通过 Controller , Service , Repository , Component , Configuration ,Bean 来声明Bean对象。通…

数学建模:K-means聚类手肘法确定k值(含python实现)

原理 当K-means聚类的k值不被指定时&#xff0c;可以通过手肘法来估计聚类数量。   在聚类的过程中&#xff0c;随着聚类数的增大&#xff0c;样本划分会变得更加精细&#xff0c;每个类别的聚合程度更高&#xff0c;那么误差平方和&#xff08;SSE&#xff09;会逐渐变小&am…

备战蓝桥杯---图论基础理论

图的存储&#xff1a; 1.邻接矩阵&#xff1a; 我们用map[i][j]表示i--->j的边权 2.用vector数组&#xff08;在搜索专题的游戏一题中应用过&#xff09; 3.用邻接表&#xff1a; 下面是用链表实现的基本功能的代码&#xff1a; #include<bits/stdc.h> using nam…

那些 C语言指针 你不知道的小秘密 (完结篇)

本篇会加入个人的所谓‘鱼式疯言’ ❤️❤️❤️鱼式疯言:❤️❤️❤️此疯言非彼疯言 而是理解过并总结出来通俗易懂的大白话, 我会尽可能的在每个概念后插入鱼式疯言,帮助大家理解的. &#x1f92d;&#x1f92d;&#x1f92d;可能说的不是那么严谨.但小编初心是能让更多人能…

蓝桥杯嵌入式第11届真题(完成) STM32G431

蓝桥杯嵌入式第11届真题(完成) STM32G431 题目 代码 程序和之前的大同小异&#xff0c;不过多解释 main.c /* USER CODE BEGIN Header */ /********************************************************************************* file : main.c* brief :…

第4讲 小程序首页实现

首页 create.vue <template><view class"vote_type"><view class"vote_tip_wrap"><text class"type_tip">请选择投票类型</text><!-- <text class"share">&#xe739;分享给朋友</text&g…

免费分享一套PyQt6学生信息管理系统 Python管理系统 Python源码,挺漂亮的

大家好&#xff0c;我是java1234_小锋老师&#xff0c;看到一个不错的PyQt6学生信息管理系统 Python管理系统 Python源码&#xff0c;分享下哈。 项目视频演示 【免费】PyQt5 学生信息管理系统 Python管理系统 Python源码 Python毕业设计_哔哩哔哩_bilibili【免费】PyQt5 学生…

康熙字典的部首里为啥没有王字旁

很多汉字的偏旁部首&#xff0c;是“王”&#xff0c;但在康熙字典的部首列表里&#xff0c;却没有它。而新华字典是有的。 这不科学啊&#xff0c;于是我还通过Unicode编码查了下康熙部首的编码部分&#xff0c;确认了一下&#xff0c;发面里面确实没有。 康熙部首&#xff08…

顺序表、链表(ArrayList、LinkedList)

目录 前言&#xff1a; 顺序表&#xff08;ArrayList&#xff09;&#xff1a; 顺序表的原理&#xff1a; ArrayList源码&#xff1a; 的含义&#xff1a;​编辑 ArrayList的相关方法&#xff1a;​编辑 向上转型List&#xff1a; 练习题&#xff08;杨辉三角&#x…

单页404源码

<!doctype html> <html> <head> <meta charset"utf-8"> <title>简约 404错误页</title><link rel"shortcut icon" href"./favicon.png"><style> import url("https://fonts.googleapis.co…

Java中抽象类和接口的区别

抽象类和接口都是 Java 中多态的常见使用方式. 都需要重点掌握. 同时又要认清两者的区别(重要!!! 常见面试题)。 核心区别: 抽象类中可以包含普通方法和普通字段, 这样的普通方法和字段可以被子类直接使用(不必重写而重写抽象方法), 而接口中不能包含普通方法&#xff08;接口…

生成式人工智能(AIGC)之最全详解图解

生成式人工智能&#xff08;AIGC&#xff09;之最全详解图解 1. AIGC的发展历程1.1 AIGC演化重要时间节点AIGC发展历程图OpenAI大语言模型发展进程 1.2技术推进路线 2.AIGC技术场景2.1 技术场景 3.1AIGC相关应用4.AIGC未来发展前景 1. AIGC的发展历程 AIGC&#xff08;AI-Gene…

ClickHouse--04--数据库引擎、Log 系列表引擎、 Special 系列表引擎

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 1.数据库引擎1.1 Ordinary 默认数据库引擎1.2 MySQL 数据库引擎MySQL 引擎语法字段类型的映射 2.ClickHouse 表引擎3.Log 系列表引擎几种 Log 表引擎的共性是&#…

任务调度

1.学习目标 1.1 定时任务概述 1.2 jdk实现任务调度 1.3 SpringTask实现任务调度 1.4 Spring-Task 分析 1.5 Cron表达式 https://cron.qqe2.com/ 2. Quartz 基本应用 2.1 Quartz 基本介绍 2.2 Quartz API介绍 2.3 入门案例 <dependency> <groupId>org.springframe…