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++解法一:

 class Solution {
public:
bool isNumber(string s) {
int len = s.size();
int left = , right = len - ;
bool eExisted = false;
bool dotExisted = false;
bool digitExisited = false;
// Delete spaces in the front and end of string
while (s[left] == ' ') ++left;
while (s[right] == ' ') --right;
// If only have one char and not digit, return false
if (left >= right && (s[left] < '' || s[left] > '')) return false;
//Process the first char
if (s[left] == '.') dotExisted = true;
else if (s[left] >= '' && s[left] <= '') digitExisited = true;
else if (s[left] != '+' && s[left] != '-') return false;
// Process the middle chars
for (int i = left + ; i <= right - ; ++i) {
if (s[i] >= '' && s[i] <= '') digitExisited = true;
else if (s[i] == 'e' || s[i] == 'E') { // e/E cannot follow +/-, must follow a digit
if (!eExisted && s[i - ] != '+' && s[i - ] != '-' && digitExisited) eExisted = true;
else return false;
} else if (s[i] == '+' || s[i] == '-') { // +/- can only follow e/E
if (s[i - ] != 'e' && s[i - ] != 'E') return false;
} else if (s[i] == '.') { // dot can only occur once and cannot occur after e/E
if (!dotExisted && !eExisted) dotExisted = true;
else return false;
} else return false;
}
// 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
if (s[right] >= '' && s[right] <= '') return true;
else if (s[right] == '.' && !dotExisted && !eExisted && digitExisited) return true;
else return false;
}
};

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

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

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

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

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

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

- 其他字符:返回false。

最后返回num && numAfterE即可。

C++解法二:

 class Solution {
public:
bool isNumber(string s) {
bool num = false, numAfterE = true, dot = false, exp = false, sign = false;
int n = s.size();
for (int i = ; i < n; ++i) {
if (s[i] == ' ') {
if (i < n - && s[i + ] != ' ' && (num || dot || exp || sign)) return false;
} else if (s[i] == '+' || s[i] == '-') {
if (i > && s[i - ] != 'e' && s[i - ] != ' ') return false;
sign = true;
} else if (s[i] >= '' && s[i] <= '') {
num = true;
numAfterE = true;
} else if (s[i] == '.') {
if (dot || exp) return false;
dot = true;
} else if (s[i] == 'e') {
if (exp || !num) return false;
exp = true;
numAfterE = false;
} else return false;
}
return num && numAfterE;
}
};

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

string s1 = ""; // True
string s2 = " 0.1 "; // True
string s3 = "abc"; // False
string s4 = "1 a"; // False
string s5 = "2e10"; // True string s6 = "-e10"; // False
string s7 = " 2e-9 "; // True
string s8 = "+e1"; // False
string s9 = "1+e"; // False
string s10 = " "; // False string s11 = "e9"; // False
string s12 = "4e+"; // False
string s13 = " -."; // False
string s14 = "+.8"; // True
string s15 = " 005047e+6"; // True string s16 = ".e1"; // False
string s17 = "3.e"; // False
string s18 = "3.e1"; // True
string s19 = "+1.e+5"; // True
string s20 = " -54.53061"; // True 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. Socket与TCP,UDP

    什么是socket 简单来说是IP地址与端口的结合协议(RFC 793) 一种地址与端口的结合描述协议 TCP/IP协议的 相关API的总称:是网络api的集合实现 涵盖了:Stream Socket ...

  2. HashMap的源码,实现原理,底层结构

    转载一遍不错的文章,让你深入了解HashMap http://www.cnblogs.com/ITtangtang/p/3948406.html

  3. mkyaffs2image 生成不了120M的镜像文件的解决方法

    下载链接:   http://download.csdn.net/download/macrocrazier/3807761 用上述下载的链接会出现Failed to execute /linuxrc ...

  4. Django REST Framework API Guide 05

    本节大纲 1.Serializer fields 2.Serializer relations Serializer fields 1.serializer 字段定义在fields.py文件内 2.导 ...

  5. 技巧性极强的strings命令

    打印文件中的可打印字符串(print the strings of printable characters in files).常用来在二进制文件中查找字符串,与grep配合使用.strings命令 ...

  6. F - Auxiliary Set HDU - 5927 (dfs判断lca)

    题目链接: F - Auxiliary Set HDU - 5927 学习网址:https://blog.csdn.net/yiqzq/article/details/81952369题目大意一棵节点 ...

  7. A Simple Problem with Integers POJ - 3468 (分块)

    题目链接:https://cn.vjudge.net/problem/POJ-3468 题目大意:区间加减+区间查询操作. 具体思路:本来是一个线段树裸题,为了学习分块就按照分块的方法做吧. 分块真的 ...

  8. ASP.NET - 学习总目录

    ASP.NET - 处理页面 ASP.NET - ADO.NET框架 ASP.NET - 创建功能菜单 ASP.NET MVC - 入门 ASP.NET MVC - 模型验证 ASP.NET MVC ...

  9. linux系统 户和账号操作

    1,基本操作要求 实现用户账号的管理,要完成的工作主要有如下几个方面: ·       用户账号的添加.删除与修改.·       用户口令的管理.·       用户组的管理. 2,用户账户添加删除 ...

  10. TCP通信实现对接硬件发送与接收十六进制数据 & int与byte的转换原理 & java中正负数的表示

    今天收到的一份需求任务是对接硬件,TCP通信,并给出通信端口与数据包格式,如下: 1.首先编写了一个简单的十六进制转byte[]数组与byte[]转换16进制字符串的两个方法,如下: /** * 将十 ...