Hard!

题目描述:

验证给定的字符串是否为数字。

例如:
"0" => true
" 0.1 " => true
"abc" => false
"1 a" => false
"2e10" => true

说明: 我们有意将问题陈述地比较模糊。在实现代码之前,你应当事先思考所有可能的情况。

解题思路:

这道验证数字的题比想象中的要复杂的多,有很多情况需要考虑。网上有很多解法,有利用有限自动机Finite Automata Machine的程序,写得简洁优雅(https://blog.csdn.net/kenden23/article/details/18696083); 还有利用正则表达式,更是写的丧心病狂的简洁(https://blog.csdn.net/fightforyourdream/article/details/12900751);这里主要还是用一般的写法,参考了另一篇博文(http://yucoding.blogspot.com/2013/05/leetcode-question-118-valid-number.html)处理各种情况。

首先,从题目中给的一些例子可以分析出来,我们所需要关注的除了数字以外的特殊字符有空格 ‘ ’, 小数点 '.', 自然数 'e/E', 还要加上正负号 '+/-", 除了这些字符需要考虑意外,出现了任何其他的字符,可以马上判定不是数字。下面我们来一一分析这些出现了也可能是数字的特殊字符:

1. 空格 ‘ ’

空格分为两种情况需要考虑,一种是出现在开头和末尾的空格,一种是出现在中间的字符。出现在开头和末尾的空格不影响数字,而一旦中间出现了空格,则立马不是数字。

解决方法:预处理时去掉字符的首位空格,中间再检测到空格,则判定不是数字。

2. 小数点 '.'

小数点需要分的情况较多,首先的是小数点只能出现一次,但是小数点可以出现在任何位置,开头(".3"), 中间("1.e2"), 以及结尾("1." ), 而且需要注意的是,小数点不能出现在自然数 'e/E' 之后,如 "1e.1" false, "1e1.1" false。还有,当小数点位于末尾时,前面必须是数字,如 "1."  true," -." false。

解决方法:开头中间结尾三个位置分情况讨论。

3. 自然数 'e/E'

自然数的前后必须有数字,即自然数不能出现在开头和结尾,如 "e" false,  ".e1" false, "3.e" false, "3.e1" true。而且小数点只能出现在自然数之前,还有就是自然数前面不能是符号,如 "+e1" false, "1+e" false。

解决方法:开头中间结尾三个位置分情况讨论。

4. 正负号 '+/-"

正负号可以在开头出现,可以在自然数e之后出现,但不能是最后一个字符,后面得有数字,如  "+1.e+5" true。

解决方法:开头中间结尾三个位置分情况讨论。

下面我们开始正式以开头、中间、结尾三个不同位置来分情况进行讨论:

1. 在讨论开头、中间、结尾三个不同位置之前做预处理,去掉字符串首尾的空格,可以采用两个指针分别指向开头和结尾,遇到空格则跳过,分别指向开头结尾非空格的字符。

2. 对首字符进行处理,首字符只能为数字或者正负号 '+/-",我们需要定义三个flag以标志我们之前检是否测到过小数点,自然数和正负号。首字符如为数字或正负号,则标记对应的flag,若不是,直接返回false。

3. 对中间字符的处理,中间字符会出现五种情况,数字,小数点,自然数,正负号和其他字符。

若是数字,标记flag并通过。

若是自然数,则必须是第一次出现自然数,并且前一个字符不能是正负号,而且之前一定要出现过数字,才能标记flag通过。

若是正负号,则之前的字符必须是自然数e,才能标记flag通过。

若是小数点,则必须是第一次出现小数点并且自然数没有出现过,才能标记flag通过。

若是其他,返回false。

4. 对尾字符处理,最后一个字符只能是数字或小数点,其他字符都返回false。

若是数字,返回true。

若是小数点,则必须是第一次出现小数点并且自然数没有出现过,还有前面必须是数字,才能返回true。

C++解法一:

  1. class Solution {
  2. public:
  3. bool isNumber(string s) {
  4. int len = s.size();
  5. int left = , right = len - ;
  6. bool eExisted = false;
  7. bool dotExisted = false;
  8. bool digitExisited = false;
  9. // Delete spaces in the front and end of string
  10. while (s[left] == ' ') ++left;
  11. while (s[right] == ' ') --right;
  12. // If only have one char and not digit, return false
  13. if (left >= right && (s[left] < '' || s[left] > '')) return false;
  14. //Process the first char
  15. if (s[left] == '.') dotExisted = true;
  16. else if (s[left] >= '' && s[left] <= '') digitExisited = true;
  17. else if (s[left] != '+' && s[left] != '-') return false;
  18. // Process the middle chars
  19. for (int i = left + ; i <= right - ; ++i) {
  20. if (s[i] >= '' && s[i] <= '') digitExisited = true;
  21. else if (s[i] == 'e' || s[i] == 'E') { // e/E cannot follow +/-, must follow a digit
  22. if (!eExisted && s[i - ] != '+' && s[i - ] != '-' && digitExisited) eExisted = true;
  23. else return false;
  24. } else if (s[i] == '+' || s[i] == '-') { // +/- can only follow e/E
  25. if (s[i - ] != 'e' && s[i - ] != 'E') return false;
  26. } else if (s[i] == '.') { // dot can only occur once and cannot occur after e/E
  27. if (!dotExisted && !eExisted) dotExisted = true;
  28. else return false;
  29. } else return false;
  30. }
  31. // Process the last char, it can only be digit or dot, when is dot, there should be no dot and e/E before and must follow a digit
  32. if (s[right] >= '' && s[right] <= '') return true;
  33. else if (s[right] == '.' && !dotExisted && !eExisted && digitExisited) return true;
  34. else return false;
  35. }
  36. };

上面的写法略为复杂,我们尝试着来优化一下,根据上面的分析,所有的字符可以分为六大类,空格,符号,数字,小数点,自然底数和其他字符,我们需要五个标志变量,num, dot, exp, sign分别表示数字,小数点,自然底数和符号是否出现,numAfterE表示自然底数后面是否有数字,那么我们分别来看各种情况:

- 空格: 我们需要排除的情况是,当前位置是空格而后面一位不为空格,但是之前有数字,小数点,自然底数或者符号出现时返回false。

- 符号:符号前面如果有字符的话必须是空格或者是自然底数,标记sign为true。

- 数字:标记num和numAfterE为true。

- 小数点:如果之前出现过小数点或者自然底数,返回false,否则标记dot为true。

- 自然底数:如果之前出现过自然底数或者之前从未出现过数字,返回false,否则标记exp为true,numAfterE为false。

- 其他字符:返回false。

最后返回num && numAfterE即可。

C++解法二:

  1. class Solution {
  2. public:
  3. bool isNumber(string s) {
  4. bool num = false, numAfterE = true, dot = false, exp = false, sign = false;
  5. int n = s.size();
  6. for (int i = ; i < n; ++i) {
  7. if (s[i] == ' ') {
  8. if (i < n - && s[i + ] != ' ' && (num || dot || exp || sign)) return false;
  9. } else if (s[i] == '+' || s[i] == '-') {
  10. if (i > && s[i - ] != 'e' && s[i - ] != ' ') return false;
  11. sign = true;
  12. } else if (s[i] >= '' && s[i] <= '') {
  13. num = true;
  14. numAfterE = true;
  15. } else if (s[i] == '.') {
  16. if (dot || exp) return false;
  17. dot = true;
  18. } else if (s[i] == 'e') {
  19. if (exp || !num) return false;
  20. exp = true;
  21. numAfterE = false;
  22. } else return false;
  23. }
  24. return num && numAfterE;
  25. }
  26. };

这道题给了例子不够用,下面这些例子是在调试的过程中出现过的例子,用来参考:

  1. string s1 = ""; // True
  2. string s2 = " 0.1 "; // True
  3. string s3 = "abc"; // False
  4. string s4 = "1 a"; // False
  5. string s5 = "2e10"; // True
  6.  
  7. string s6 = "-e10"; // False
  8. string s7 = " 2e-9 "; // True
  9. string s8 = "+e1"; // False
  10. string s9 = "1+e"; // False
  11. string s10 = " "; // False
  12.  
  13. string s11 = "e9"; // False
  14. string s12 = "4e+"; // False
  15. string s13 = " -."; // False
  16. string s14 = "+.8"; // True
  17. string s15 = " 005047e+6"; // True
  18.  
  19. string s16 = ".e1"; // False
  20. string s17 = "3.e"; // False
  21. string s18 = "3.e1"; // True
  22. string s19 = "+1.e+5"; // True
  23. string s20 = " -54.53061"; // True
  24.  
  25. string s21 = ". 1"; // False

这道题实在是太烦了,情况太多了,简直是无法无天呀~

LeetCode(65):有效数字的更多相关文章

  1. C#版 - Leetcode 65. 有效数字 - 题解

    版权声明: 本文为博主Bravo Yeung(知乎UserName同名)的原创文章,欲转载请先私信获博主允许,转载时请附上网址 http://blog.csdn.net/lzuacm. Leetcod ...

  2. Java实现 LeetCode 65 有效数字

    65. 有效数字 验证给定的字符串是否可以解释为十进制数字. 例如: "0" => true " 0.1 " => true "abc&q ...

  3. [LeetCode] 65. 有效数字

    题目链接 : https://leetcode-cn.com/problems/valid-number/ 题目描述: 验证给定的字符串是否可以解释为十进制数字. 例如: "0"` ...

  4. leetCode 65.Valid Number (有效数字)

    Valid Number  Validate if a given string is numeric. Some examples: "0" => true " ...

  5. LeetCode 65 Valid Number

    (在队友怂恿下写了LeetCode上的一个水题) 传送门 Validate if a given string is numeric. Some examples: "0" =&g ...

  6. [LeetCode] 65. Valid Number 验证数字

    Validate if a given string can be interpreted as a decimal number. Some examples:"0" => ...

  7. Leetcode 65 Valid Number 字符串处理

    由于老是更新简单题,我已经醉了,所以今天直接上一道通过率最低的题. 题意:判断字符串是否是一个合法的数字 定义有符号的数字是(n),无符号的数字是(un),有符号的兼容无符号的 合法的数字只有下列几种 ...

  8. LeetCode(65)-Power of Four

    题目: Given an integer (signed 32 bits), write a function to check whether it is a power of 4. Example ...

  9. [leetcode]65. Valid Number 有效数值

    Validate if a given string can be interpreted as a decimal number. Some examples:"0" => ...

  10. LeetCode (65):Same tree

    Total Accepted: 83663 Total Submissions: 200541 Difficulty: Easy Given two binary trees, write a fun ...

随机推荐

  1. webwork框架

    以前都没有用过WebWork这个框架,只是听说过.没想到现在要用,所以就自学了一下.做了个小例子给大家分享下中间遇到的苦难和经验. 准备工作:首先要去下载WebWork框架的开发包.我用的2.2.6版 ...

  2. linux C遍历目录下文件

    参考链接: http://blog.sina.com.cn/s/blog_626b7339010161tr.html

  3. mysql 原理 ~ LRU 算法与buffer_pool

    一 简介:针对查询和事务的页在内存中的处理,是如何进行的 二 LRU算法 普通 : 实现的是末尾淘汰法,当整个链表已满时,淘汰尾部,将新的数据页加入头部 mysql_lru改进 : 分为两部分 yan ...

  4. Jedis(java操作redis数据库技术)

    Redis有什么命令,Jedis就有什么方法. 客户端无法连接时,需要考虑防火墙配置,比如6379端口是否开放,也可以直接关闭防火墙. Jedis连接池: import org.junit.Test; ...

  5. RabbitMQ简单应用の简单队列

    (1)首先创建一个maven项目: pom.xml,重点是配置RabbitMQ <dependencies> <dependency> <groupId>junit ...

  6. Debian 9 美化界面

    Debian 桌面美化 安装 gnome-tweak-tool aptitude install gnome-tweak-tool 登陆gnome-look下载主题包 gnome-look上有很多主题 ...

  7. 在 sql server 中,查询 数据库的大小 和 数据库中各表的大小

    其实本来只想找一个方法能查询一下 数据库 的大小,没想到这个方法还能查询数据库中 各个数据表 的大小,嗯,挺好玩的,记录一下. MSDN资料:https://msdn.microsoft.com/zh ...

  8. Deep Learning Tutorial - Multilayer perceptron

    Multilayer perceptron:多层感知器 本节实现两层网络(一个隐层)作为分类器实现手写数字分类.引入的内容:激活函数(双曲正切.L1和L2正则化).Theano的共享变量.grad.f ...

  9. Go语言中的map

    map是一个集合,可以使用类似处理数组和切片的方式迭代map中的元素.但map是无序的集合.无序的原因是map的实现使用了散列表. map的创建并初始化主要是两种方式: 1.内置的make函数 2.使 ...

  10. pycharm 中自动补全代码提示前符号 p,m ,c,v, f 是什么意思

    是自动补全的变量的类别p:parameter 参数m:method 方法c:class 类 v:variable 变量f:function 函数