本文始发于个人公众号:TechFlow,原创不易,求个关注

今天是LeetCode专题的第38篇文章,我们一起来看看第65题,Valid Number。

曾经我们聊到过算法当中的一个类别——模拟题。所谓的模拟题就是题面非常简单,也不涉及任何复杂的算法,但是要实现的功能比较麻烦,非常考验人思维的缜密程度,很难写出bug-free的代码来。今天要说的65题可以说是其中的典范,它的题面非常简单,简单到只有一句话,但是要实现非常麻烦,比较锻炼人的耐心,以至于反对的人是点赞的9倍,我们一起来看看。

题面

给定一个字符串,判断它是否是一个合法的浮点数。

从题面来看只有一句话,似乎非常简单。但是实际上如果你仔细研究一下样例和提示,会发现事情可能和你想的不太一样。

样例

"0" => true
" 0.1 " => true
"abc" => false
"1 a" => false
"2e10" => true
" -90e3 " => true
" 1e" => false
"e3" => false
" 6e-1" => true
" 99e2.5 " => false
"53.5e93" => true
" --6 " => false
"-+3" => false
"95a54e53" => false

提示

我们有意将问题陈述地比较模糊。在实现代码之前,你应当事先思考所有可能的情况。这里给出一份可能存在于有效十进制数字中的字符列表:

数字 0-9

指数 - "e"

正/负号 - "+"/"-"

小数点 - "."

当然,在输入中,这些字符的上下文也很重要。

不知道大家感受到了没有,这其中的情况不少,涉及的符号就很多。除了基本的数字之外,还有小数点、空格、正负号、e。这些符号带来的合法和非法的情况都很多,更何况这些符号之间还可以互相组合,又会引申出新的情况。

更坑爹的一点是,这题简单粗暴,只有这一个解法,我们别无选择,只有覆盖所有的情况才能通过。所以如果你试着去想清楚所有的这些情况,你会发现这是非常困难的一件事,甚至可能会越想情况越多,觉得怎么也理不清楚,即使你理出了很多情况,也不知道是否有遗漏,很容易让人抓狂并且心烦气躁,明明很简单的问题做不出来,感受肯定不好。先别着急,这正是模拟题考验人的地方,它考验的不仅是思维,也是心态。

所以,先深吸一口气,冷静下来,我们仔细地分析一下这些情况。

解法

我们从列举所有的情况入手是非常困难的,因为符号之间互相组合的情况实在是很多,一一列举全并且用代码实现的代价很大。我们先把这些烦人的情况放在一边,我们先来思考一下问题所在。

这个问题的核心就是判断浮点数是否合法,合法的浮点数的情况也是不少的,但这些情况虽然多,彼此之间是有联系的。最起码我们可以发现符号之间的顺序,如果我们把一个合法的浮点数进行拆分,它大概可以分成以下几个部分。

首先是符号位,表示这个数是正数还是负数。题目当中没有明说,但是我们可以猜测出来,正数用正号表示也是合法的。

第二个部分是科学记数法的前半部分,它可以是一个小数。

第三个部分是e,即科学记数法当中的e。

最后一个部分是整数部分,表示e的指数,根据科学记数法的定义,必然是一个整数。但是可以是负数。

当我们把这四个部分列举出来之后,再来进行判断就容易多了。因为这四个部分是有顺序的,我们只需要判断它们顺序的合理性就可以了。根据顺序的合理性,我们可以进一步推测出每一个符号允许出现的位置,所有和预期位置不符的符号都是非法的。

根据这一点我们可以推导出一些结论:

  1. 空格只能出现在首尾,出现在中间一定是非法的。
  2. 正负号只能出现在两个地方,第一个地方是数字的最前面,表示符号。第二个位置是e后面,表示指数的正负。如果出现在其他的位置一定也是非法的。
  3. 数字,数字没有特别的判断,本题当中没有前导0的问题。
  4. e只能出现一次,并且e之后一定要有数字才是合法的,123e这种也是非法的。
  5. 小数点,由于e之后的指数一定是整数,所以小数点最多只能出现一次,并且一定要在e之前。所以如果之前出现过小数点或者是e,再次出现小数点就是非法的。

当我们把每一个符号合法的情况梳理清楚之后,会发现其实也没有那么复杂,情况也没有那么多。这其实也是常用套路,我们把互相耦合的一些变量拆分开了,彼此互不影响。这样我们就可以单独考虑这其中的每个零件,而不用面对它们互相耦合的复杂情况了。

我们把刚才梳理出来的全部用代码实现就可以通过这题了:

class Solution:
def isNumber(self, s: str) -> bool:
s = s.strip()
numbers = [str(i) for i in range(10)]
n = len(s) # 用4个标记记录e和小数点以及数字和e之后的数字有无出现过
e_show_up, dot_show_up, num_show_up, num_after_e = False, False, False, False for i in range(n):
c = s[i]
# 如果是数字,则将数字和e后出现的数字都标记为true
# 没有e的浮点数也认为e之后出现过数字
if c in numbers:
num_show_up = True
num_after_e = True
# 如果是正负号,只有出现在首位或者是e后面才是合法
elif c in ('+', '-'):
if i > 0 and s[i-1] != 'e':
return False
# 如果是小数点,那么必须保证e和小数点都没有出现过
elif c == '.':
if dot_show_up or e_show_up:
return False
dot_show_up = True
# 如果是e,要保证已经有数字出现,并且e没有出现过
elif c == 'e':
if e_show_up or not num_show_up:
return False
e_show_up = True
num_show_up = False
# 其他情况都视为非法
else:
return False return num_show_up and num_after_e

总结

这题我们看代码好像也不复杂,但是想要把这么多条件都梳理清楚,写出这样简单的代码也不是一件容易的事情。必须建立在我们对问题有了充分的思考的基础上,其实我们的代码还疏漏了一个条件就是前导零的情况。如果0出现在数字最前面其实也是非法的,不过这题当中没有针对这样的case,但实际上我们是应该考虑的,这里也是我偷懒了。

很多人很讨厌模拟题,包括我在内,原因就是情况太多很恶心人,经常会中招遗漏一些情况。看看这题的评分也能看得出来,点赞的只有678,反对的却又4572,可见一斑。但其实模拟题也是一种对思维的锻炼,需要我们有冷静的思维和理智的分析,这也是一个优秀的选手必不可少的。希望大家都能攻克这道难关。

今天的文章就到这里,原创不易,扫码关注我,获取更多精彩文章。

这道LeetCode题究竟有什么坑点,让它的反对是点赞的9倍?的更多相关文章

  1. leetcode题库

    leetcode题库 #题名题解通过率难度出现频率  1 两数之和     46.5%简单2 两数相加     35.5%中等3 无重复字符的最长子串     31.1%中等4 寻找两个有序数组的中位 ...

  2. 简单的leetcode题

    简单的leetcode题 环绕字符串中唯一的子字符串 把字符串 s 看作是\("abcdefghijklmnopqrstuvwxyz"\)的无限环绕字符串,所以 s 看起来是这样的 ...

  3. LeetCode42题,单调栈、构造法、two pointers,这道Hard题的解法这么多?

    本文始发于个人公众号:TechFlow,原创不易,求个关注 今天是LeetCode专题的第23篇文章. 今天来看一道很有意思的题,它的难度是Hard,并且有许多种解法. 首先我们来看题面,说是我们有若 ...

  4. C++/Java小白解Leetcode题,发现了知识盲区……

    一.初见LeetCode 大一时候学习C++,根据课程一直在PTA平台做题目,数据结构和算法的作业题目也是在PTA.后来发现牛客网学习资源也很丰富,孤陋寡闻,前几个月在知道LeetCode这个平台,跟 ...

  5. HDU5003:Osu!(签到题)HDU5038:(签到题,题意很坑)

    HDU 5003 水题,直接上代码(因为题意读错了,WA了一遍). #include <iostream> #include <string.h> #include <s ...

  6. LeetCode题库整理(自学整理)

    1. Two Sum 两数之和       来源:力扣(LeetCode) 题目:给定一个整数数组和一个目标值,找出数组中和为目标值的两个数.你可以假设每个输入只对应一种答案,且同样的元素不能被重复利 ...

  7. Leetcode题1

    Given an array of integers, find two numbers such that they add up to a specific target number. The ...

  8. leetcode题库解答源码(python3)

    下面和大家分享本人在leetcode上已经ace的题目源码(python3): 本人会持续更新!- class Leetcode_Solution(object): def twoSum_1(self ...

  9. 牛客网 Wannafly挑战赛 C 列一列 简单题 (题目有点坑)

    链接:https://www.nowcoder.com/acm/contest/71/C来源:牛客网 题目描述 小W在计算一个数列{An},其中A1=1,A2=2,An+2=An+1+An.尽管他计算 ...

随机推荐

  1. Java锁之自旋锁

    Java锁之自旋锁 自旋锁:spinlock,是指尝试获取锁的线程不会立即阻塞,而是采用循环的方式去尝试获取锁,这样的好处是减少线程上下文切换的消耗,缺点是循环会消耗CPU 原来提到的比较并交换,底层 ...

  2. 【转帖】Python 重复造轮子/造轮子找模子,你都应该熟读该文

    Chardet,字符编码探测器,可以自动检测文本.网页.xml的编码. colorama,主要用来给文本添加各种颜色,并且非常简单易用. Prettytable,主要用于在终端或浏览器端构建格式化的输 ...

  3. How to skip all the wizard pages and go directly to the installation process?

    https://stackoverflow.com/questions/22183811/how-to-skip-all-the-wizard-pages-and-go-directly-to-the ...

  4. Zabbix CPU utilization监控参数

    工作中查看Zabbix linux 监控项的时候对linux 监控的cpu使用的各个参数没怎么明白,特意查看了下资料 Zabbix linux模板下的CPU utilization是自带的监控Linu ...

  5. apollo 项目配置中心开源框架部署

    apollo 于我带来的好处 1. 项目之前的配置信息全部都在 resources 目录下,当然这里我使用的是 Spring Boot 搭建的项目.使用 apollo 后,配置信息全部转移到 apol ...

  6. 全栈必备Log日志

    Log日志,不论对开发者自身,还是对软件系统乃至产品服务都是非常重要的事情.每个开发者都接触过日志,以至于每个人对日志的了解都会有所不同. 什么是日志 日志是什么呢?老码农看来,日志是带有明确时间标记 ...

  7. 演示:配置日志发送到syslog日志服务器

    演示目标:配置网络环境中的交换机和路由器将日志发送到syslog日志服务器. 演示环境:如下图10.54所示的演示环境. 演示背景:要求部署网络中的syslog服务器,集中的收集交换机S1和路由器R1 ...

  8. Codeforces Round 623(Div. 2,based on VK Cup 2019-2020 - Elimination Round,Engine)D. Recommendations

    VK news recommendation system daily selects interesting publications of one of n disjoint categories ...

  9. 一只简单的网络爬虫(基于linux C/C++)————浅谈并发(IO复用)模型

    Linux常用的并发模型 Linux 下设计并发网络程序,有典型的 Apache 模型( Process Per Connection ,简称 PPC ), TPC ( Thread Per Conn ...

  10. 【摘抄】深入解析Windows操作系统

    一.线程是一个进程内部的实体,也是Windows执行此进程时的调度实体.若没有线程,进程的程序将不可能运行.线程包含以下部件: 1.一组代表处理器状态的CPU寄存器中的内容. 2.两个栈:一个用于线程 ...