LeetCode 91,点赞和反对五五开,这题是好是坏由你来评判
本文始发于个人公众号:TechFlow,原创不易,求个关注
今天是LeetCode专题的第57篇文章,我们一起来看看LeetCode第91题,解码方法(Decode ways)。
这道题官方给定的难度是Medium,点赞2680,反对2845,通过率24.5%。从通过率上来看这道题似乎很难,甚至比很多Hard难度的问题还要难。从点赞和反对的数量来看,这道题应该算是褒贬不一,两边阵营的人数都很多。一般来说题目的评价都是一边倒为主,这种情况很少出现。首先值得一说的是,这道题我个人肯定认为是值得一做的,至于它是否是一道好问题呢?这个问题就留给大家自己回答吧。
首先我们来看下这道题的题意。
题意
在传送消息的时候我们可以把字母映射成数字,比如A映射成1,B映射成2,Z映射成26。我们这里假设用到的字母只有大写的,也就是说我们用26个数字就可以代表A到Z的所有字母。
现在我们得到了一串数字连成的字符串,想要将它还原成原本字母组成的信息,请问它一共有多少种还原的方法?
样例
Input: "12"
Output: 2
Explanation: It could be decoded as "AB" (1 2) or "L" (12).
Input: "226"
Output: 3
Explanation: It could be decoded as "BZ" (2 26), "VF" (22 6), or "BBF" (2 2 6).
题解
我们观察一下样例,比如12可以理解成12这个字符也就是L,也可以理解成1和2两个字符拼接而成。同样226有三种还原的方法,分别是(2, 2, 6), (22, 6), (2, 26)。我们只需要返回所有可能的数量即可。
这道题看起来没有头绪,但是当我们仔细分析一下其中的情况,其实并不复杂。首先对于字符串当中的每一位来说,只有0到9这10种可能性。我们逐一来考虑,首先如果是0,由于我们的A映射的是1,所以0只能和前面一个数字凑成10或者是20,如果前一位不是1或者是2,那么说明这个字符串是非法的,也就是没有办法还原。
如果某一位是1-9当中的数字,它都可以单独成为一个字母。我们再考虑它的前一位,它的前一位只有1和2这两种可能可以构成新的组成。这里要注意,如果它的前一位是2的话,那么当前位必须要小于6,因为英文字母最多只到26。所以这里也需要进行一个特殊判断,除此之外,就没有其他情况了。
这些可能性都列举出来之后,剩下的就简单了,比如我们可以用深搜来搜索所有解的可能性。由于我们已经列举出了所有的情况,所以这段代码并不难写,但是想要一次就写对也不容易。
class Solution:
def numDecodings(self, s: str) -> int:
n = len(s)
ret = 0
def dfs(i):
nonlocal ret
if i >= n:
ret += 1
return
# 当前位如果是0则说明无解,return
# 当前位为0说明上一位不是1或者2
if s[i] == '0':
return
# 递归单个的情况
dfs(i+1)
# 判断下一位能否构成组合
if i+1 < n and (s[i] == '1' or (s[i] == '2' and ord(s[i+1]) <= ord('6'))):
dfs(i+2)
dfs(0)
return ret
搜索算法固然可以解,但是一定会超时。这一点也不难想明白,当我们的字符串长度大了之后,带来的解的可能性是非常多的。最极端的情况下,比如每一位都是1,它都可以单独作为一个字符也可以和下一位组合成11构成新的字符。这样的情况总数是以斐波那契数列递增的,n不需要多大带来的解的数量就是天文数字了。
使用搜索算法我们需要穷举每一种情况,哪怕寻找每一个解只需要的复杂度也是无法抗住的。
所以我们必须要想一些更优的方法,这个方法也不难想,就是动态规划。
我们分析一下会发现每一位数字能够组成的解只和它的前一位有关,和后面的都没有关系。这样的话显然是满足动态规划的无后效性的。也就是说前面的字符组合的情况不会影响后面的解。
我们假设dp[i]存储的是前i个数字构成的解的数量,对于s[i]来说有10种情况,分别是0到9。如果s[i]为0,那么s[i-1]如果是1或者是2的话,只有一种情况,就是0和s[i-1]组成10或者是20。那么dp[i] = dp[i-2]。
如果s[i]不为0,那么s[i]可以选择单独成为一个字符,那么dp[i] = dp[i-1]。当然如果s[i-1]是1或者是2的话,s[i]也可以选择和s[i-1]合起来组成一个字符。那么这样的情况下,dp[i]需要再额外增加dp[i-2],也就是dp[i]构成的答案可能性增加了。
如果把这些状态之间的转移情况都梳理清楚了,那么这个代码肯定不难写的。
class Solution:
def numDecodings(self, s: str) -> int:
n = len(s)
# 为了简化判断,我们把s前面加上0,这样字符串下标从1开始
s = '0' + s
dp = [0 for _ in range(n+2)]
dp[0] = 1
for i in range(1, n+1):
# 如果当前位0,那么判断前一位是否是1或2
# 否则一定无解
if s[i] == '0':
if i > 1 and s[i-1] in ('1', '2'):
dp[i] = dp[i-2]
else:
return 0
continue
dp[i] = dp[i-1]
# 能和前一位构成字符,那么加上dp[i-2]的数量
if i > 1 and s[i-1] == '1' or s[i-1] == '2' and ord(s[i]) <= ord('6'):
dp[i] += dp[i-2]
return dp[n]
总结
从动态规划的角度上来看,这道题并不算困难,说是迎刃而解也不为过。但如果没有想到动态规划,纠结于搜索算法的话那么可能一直都没有办法AC。
我不清楚给差评的是否都是后一种情况,但单纯从题目的质量上来说,这道题的质量是不错的,是一道很不错的联系动态规划的习题,因此建议大家有时间都能体会一下。
今天的文章到这里就结束了,如果喜欢本文的话,请来一波素质三连,给我一点支持吧(关注、转发、点赞)。
- END -
LeetCode 91,点赞和反对五五开,这题是好是坏由你来评判的更多相关文章
- leetcode@ [91] Decode Ways (Dynamic Programming)
https://leetcode.com/problems/decode-ways/ A message containing letters from A-Z is being encoded to ...
- Leetcode 91. Decode Ways 解码方法(动态规划,字符串处理)
Leetcode 91. Decode Ways 解码方法(动态规划,字符串处理) 题目描述 一条报文包含字母A-Z,使用下面的字母-数字映射进行解码 'A' -> 1 'B' -> 2 ...
- [转帖]鲁大师Q3季度PC处理器排行:AMD、Intel终于五五开了
鲁大师Q3季度PC处理器排行:AMD.Intel终于五五开了 https://www.cnbeta.com/articles/tech/902375.htm 近日,鲁大师发布了Q3季度PC处理器排行. ...
- 《学习OpenCV》练习题第五章第二题abc
代码: #include <stdio.h> #include <opencv/highgui.h> #include <opencv/cv.h> #include ...
- 《学习OpenCV》练习题第五章第一题ab
这道题是载入一幅带有有趣纹理的图像并用不同的模板(窗口,核)大小做高斯模糊(高斯平滑),然后比较用5*5大小的窗口平滑图像两次和用11*11大小的窗口平滑图像一次是否接近相同. 先说下我的做法,a部分 ...
- 20155326 第五周加分题--mybash的实现
第五周加分题--mybash的实现 题目要求 1.使用fork,exec,wait实现mybash 2.写出伪代码,产品代码和测试代码 3.发表知识理解,实现过程和问题解决的博客(包含代码托管链接) ...
- 第五周加分题--mybash的实现
第五周加分题--mybash的实现 题目要求 1.使用fork,exec,wait实现mybash 2.写出伪代码,产品代码和测试代码 3.发表知识理解,实现过程和问题解决的博客(包含代码托管链接) ...
- 第五周 加分题-mybash的实现
第五周 加分题-mybash的实现 使用fork,exec,wait实现mybash 产品代码 #include <stdio.h> #include <stdlib.h> # ...
- 2017-2018-1 20155320 第五周 加分题-mybash的实现
2017-2018-1 20155320 第五周 加分题-mybash的实现 使用fork,exec,wait实现mybash 写出伪代码,产品代码和测试代码 发表知识理解,实现过程和问题解决的博客( ...
随机推荐
- Trie——解决字符串搜索、异或最值问题
Trie--解决字符串搜索.异或最值问题 在说到Trie之前,我们设想如下问题: 给我们1e5个由小写字母构成的不重复的字符串,每个字符串长度不超过6,之后是1e5次查询操作,每次给我们一个字符串,要 ...
- Spring-Boot 多数据源配置+动态数据源切换+多数据源事物配置实现主从数据库存储分离
一.基础介绍 多数据源字面意思,比如说二个数据库,甚至不同类型的数据库.在用SpringBoot开发项目时,随着业务量的扩大,我们通常会进行数据库拆分或是引入其他数据库,从而我们需要配置多个数据源. ...
- .clearfix 清除浮动,@import
我们知道,在网页的DIV+CSS布局中,很多时候要用到浮动. 既然有浮动,那就有清除浮动. 清除浮动有很多种方式,而在实际项目中,比较常用的是这一种. .clearfix:after { conten ...
- Python 简明教程 --- 24,Python 文件读写
微信公众号:码农充电站pro 个人主页:https://codeshellme.github.io 过去的代码都是未经测试的代码. 目录 无论是哪种编程语言,IO 操作都是非常重要的部分.I 即Inp ...
- 设计模式:fly weight模式
目的:通过共享实例的方式来避免重复的对象被new出来,节约系统资源 别名:享元模式 例子: class Char //共享的类,轻量级 { char c; public: Char(char c) { ...
- Go操作腾讯云COS对象存储的简单使用案例
准备环境 安装Go环境 Golang:用于下载和安装 Go 编译运行环境,请前往 Golang 官网进行下载 安装SDK go get -u github.com/tencentyun/cos-go- ...
- jsp课堂笔记5 Java servlet
servlet的创建 servlet类就是一个包含javax.servlet.http包中的HttpServlet类 部署web.xml文件 在<sevlet>标签中创建 <serv ...
- OpenWrt 编译分割
本文主要参考:http://macbruins.com/2011/05/08/downloading-sources-for-building-openwrt/ OpenWrt系统在buildroot ...
- sed 指定行范围匹配
sed -n '5,10{/pattern/p}' file sed是一个非交互性性文本编辑器,它编辑文件或标准输入 导出的文件拷贝.标准输入可能是来自键盘.文件重定向.字符串或变量,或者是一个管道文 ...
- html中input提示文字样式修改
在很多网站上我们都看到input输入框显示提示文字,让我们一起来看看如果在input输入框中显示提示文字.我们只需要在<input>标签里添加:placeholder="提示文字 ...