当前位置: 首页 > news >正文

91.解码方法

dp问题描述

求解码方法总数
我们在学习Huffman编码时都知道,编码过程中出现的前缀覆盖问题会导致编码出现歧义,所以我们通过构建哈夫曼树的方法来求出最短且没有歧义的前缀编码。那么这个题目就是给你一个存在前缀覆盖问题的编码方案,让你求出指定消息的所有解码方案
到这里问题其实我们已经明白的差不多了,但是他怎么能和动态规划沾上边儿呢?这个题目的状态表示是什么?状态转移方程应该怎么写?
在这里插入图片描述

确定本题的状态表示

dp[i]表示的是s[0]~s[i]所构成的子字符串的解码方案的总数

确定本题的状态转移方程

假如说我们现在要确定dp[i],根据我们的经验,dp[i]绝大部分情况下都能用dp[i-1]和dp[i-2]来表示,即dp[i] = f(dp[i-1],dp[i-2] )
那现在我们就要去想如何用dp[i-1]和dp[i-2]去表示dp[i]
对于本题来说,假如s[i]单独解码以及s[i-1]和s[i]联合解码,都可以对应一个字母映射,那么dp[i]=dp[i-1]+dp[i-2]
可是由于并不是任意两个数字结合都能映射到一个字母(值大于等于27的两位数就不行),也不是任意一个数字都能映射到一个字母(0不行),因此我们在从左到右遍历的时候就要考虑下面的情况

  1. s[i]=='0'时应该怎么处理?
  2. s[i-1]=='0'时应该怎么处理?
  3. s[i-1]与s[i]组合成的两位数大于26该怎么处理?

其实最折磨的就是s[i]=='0'的处理,s[i-1]的情况不同,对应的dp[i]的递推式也不相同。有可能解不出来,比如s[0]='0',连续的两个零,或者80,也有可能可以解出来,比如20
你要综合考虑,算出每一种情况下dp数组的递推表达式

填表求值

根据初始条件和状态转移方程,确定填表顺序,进而逐步填满dp表,最终返回题目要的结果

代码实现

我的代码

class Solution {
public:int numDecodings(string s) {int n=s.size();if(n==0||s[0]=='0') return 0;else if(n==1) return 1;vector<int> dp(n+1);dp[0]=1;dp[1]=1;for(int i=1;i<n;i++){int tmp=(s[i-1]-'0')*10+s[i]-'0';if(tmp==0||(s[i]=='0'&&tmp>=30)) return 0;if(tmp>=27) dp[i+1]=dp[i];else if(s[i]=='0')dp[i+1]=dp[i-1];else if(s[i-1]=='0') dp[i+1]=dp[i];else dp[i+1]=dp[i]+dp[i-1];// cout << "s[i]="<< s[i]<<" dp["<<i<<"]="<<dp[i]<< endl;}return dp[n];}
};

从我们上面的代码可以看出,dp[i+1]理想情况下应该等于dp[i]+dp[i-1],遇到特殊情况可能不加dp[i],也可能不加dp[i-1],但这个题目的这种情况实在是太复杂了。所以我们按照正难则反的思想,只讨论什么情况下dp[i+1]应该+=dp[i],什么情况下dp[i+1]应该+=dp[i-1],满足条件我就加,不满足条件我就不加。这样可能会好想一点。

看了网上的优质解法,感觉和我的思路也不太一样。但是今天实在是没有精力继续研究了,先把它放这儿吧,以后有空。再来仔细看看

int numDecodings(string s) {int n = s.size();vector<int> dp(n);dp[0] = s[0] != '0';if (n == 1) return dp[0];if (s[0] != '0' && s[1] != '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 t = (s[i - 1] - '0') * 10 + s[i] - '0';if (t >= 10 && t <= 26) dp[i] += dp[i - 2];}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[ - 1] != '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];}
};
http://www.dtcms.com/a/335435.html

相关文章:

  • GaussDB 数据库架构师修炼(十三)安全管理(5)-全密态数据库
  • 17.5 展示购物车缩略信息
  • JMeter(进阶篇)
  • 3D打印——给开发板做外壳
  • 蓝凌EKP产品:JSP 性能优化和 JSTL/EL要点检查列表
  • Trae 辅助下的 uni-app 跨端小程序工程化开发实践分享
  • Docker之自定义jkd镜像上传阿里云
  • Spring AI 集成阿里云百炼平台
  • vscode无法检测到typescript环境解决办法
  • SpringCloud 03 负载均衡
  • 向量数据库基础和实践 (Faiss)
  • QT 基础聊天应用项目文档
  • Flutter vs Pygame 桌面应用开发对比分析
  • Android原生(Kotlin)与Flutter混合开发 - 设备控制与状态同步解决方案
  • 安卓开发者自学鸿蒙开发2页面高级技巧
  • 第一阶段总结:你的第一个3D网页
  • 【牛客刷题】成绩统计与发短信问题详解
  • OpenMemory MCP发布!AI记忆本地共享,Claude、Cursor一键同步效率翻倍!
  • 【FreeRTOS】刨根问底6: 应该如何防止任务栈溢出?
  • JavaScript性能优化实战(四):资源加载优化
  • FreeRTOS源码分析八:timer管理(一)
  • Hunyuan-GameCraft:基于混合历史条件的高动态交互游戏视频生成
  • 健身房预约系统SSM+Mybatis实现(三、校验 +页面完善+头像上传)
  • 基于Node.js+Express的电商管理平台的设计与实现/基于vue的网上购物商城的设计与实现/基于Node.js+Express的在线销售系统
  • Visual Studio Code 基础设置指南
  • iSCSI服务配置全指南(含服务器与客户端)
  • 12.web api 3
  • Docker入门:容器化技术的第一堂课
  • Chrome插件开发实战:todoList 插件
  • IP 分片和组装的具体过程