题目
65.
有效数字
难度: 困难
有效数字 (按顺序)可以分成以下几个部分:
一个 小数 或者 整数
(可选)一个 'e'
或 'E'
,后面跟着一个
整数
小数 (按顺序)可以分成以下几个部分:
(可选)一个符号字符('+'
或 '-'
)
下述格式之一:
至少一位数字,后面跟着一个点 '.'
至少一位数字,后面跟着一个点 '.'
,后面再跟着至少一位数字
一个点 '.'
,后面跟着至少一位数字
整数 (按顺序)可以分成以下几个部分:
(可选)一个符号字符('+'
或 '-'
)
至少一位数字
部分有效数字列举如下:
["2", "0089", "-0.1", "+3.14", "4.", "-.9", "2e10", "-90E3", "3e+7", "+6e-1", "53.5e93", "-123.456e789"]
部分无效数字列举如下:
["abc", "1a", "1e", "e3", "99e2.5", "--6", "-+3", "95a54e53"]
给你一个字符串 s
,如果 s
是一个
有效数字 ,请返回 true
。
示例 1:
输入: s = "0"
输出: true
示例 2:
输入: s = "e"
输出: false
示例 3:
输入: s = "."
输出: false
示例 4:
输入: s = ".1"
输出: true
提示:
1 <= s.length <= 20
s
仅含英文字母(大写和小写),数字(0-9
),加号
'+'
,减号 '-'
,或者点 '.'
。
分类讨论
校验一个数字是否有效,一个简单的思路就是根据题目所给的信息进行分类讨论
注意到一个有效数字中有两个“关键字”,或者说是标识符,分别是
一个 'e'
或 'E'
, 这是区分
科学计数法数字 和普通数字 的标志
小数点
'.'
,这是区分小数 和整数 的标志
所以对于两个标志的识别和查找是分类讨论的前提,然后按照题目信息进行分类查找
先遍历一次字符串查找 'e'
或 'E'
的位置,分三种情况
没有 'e'
或 'E'
,说明这是一个 小数 或
整数, 标识符设置到末尾
有且只有一个 'e'
或 'E'
,且位置不在开头结尾,记录其位置,可以将数字分为两半,前面是小数或整数后面是整数
不止一个 'e'
或 'E'
或位于开头结尾,这是不合理的,直接返回 false
在前半段查找小数点
'.'
(没有指数的情况下指数标识符因为在末尾所以是查找整个字符串),同样有三种情况
没有小数点,那就是整数了,同样把小数标识符设置到末尾
有且只有一个小数点,说明是一个小数,记录其位置
不止一个小数点,这是不合理的,直接返回 false
对整数分情况讨论
有没有符号字符('+'
或
'-'
),是不是有且只有一个
是否有至少一位数字(0开头的数字是合法的)
对小数分情况讨论,小数比整数复杂些
有没有符号字符('+'
或
'-'
),是不是有且只有一个
小数点前后至少一个位置有数字
ps:这种情况复杂的写写注释有助于防止自己写迷糊,也方便debug,毕竟各种稀奇古怪的测试用例想一遍就过对于逻辑思维还是有点挑战的~
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 class Solution {public : bool isNumber (string s) { int n = s.size (); int e = n; for (int i = 0 ; i < n; ++i) { if (s[i] == 'e' || s[i] == 'E' ) { if (e != n) return false ; else e = i; } } if (e == 0 ) return false ; int dot = e; for (int i = 0 ; i < e; ++i) { if (s[i] == '.' ) { if (dot != e) return false ; else dot = i; } } int c = 0 ; if (dot == e) { if (s[c] == '+' || s[c] == '-' ) { ++c; if (c == dot) return false ; } while (c < dot) { int tmp = s[c++] - '0' ; if (tmp < 0 || tmp > 9 ) return false ; } } else { if (s[c] == '+' || s[c] == '-' ) ++c; if (c == dot) { if ((c++) + 1 == e) return false ; while (c < e) { int ttt = s[c++] - '0' ; if (ttt < 0 || ttt > 9 ) return false ; } } else { while (c < dot) { int ttt = s[c++] - '0' ; if (ttt < 0 || ttt > 9 ) return false ; } c = dot + 1 ; while (c < e) { int ttt = s[c++] - '0' ; if (ttt < 0 || ttt > 9 ) return false ; } } } if (++e == n) return false ; if (e < n && (s[e] == '+' || s[e] == '-' )) { if (++e == n) return false ; } while (e < n) { int sts = s[e++] - '0' ; if (sts < 0 || sts > 9 ) return false ; } return true ; } };
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 class Solution { public boolean isNumber (String s) { char [] ss = s.toCharArray(); int n = ss.length; int e = n; for (int i = 0 ; i < n; ++i) { if (ss[i] == 'e' || ss[i] == 'E' ) { if (e != n) return false ; else e = i; } } if (e == 0 ) return false ; int dot = e; for (int i = 0 ; i < e; ++i) { if (ss[i] == '.' ) { if (dot != e) return false ; else dot = i; } } int c = 0 ; if (dot == e) { if (ss[c] == '+' || ss[c] == '-' ) { ++c; if (c == dot) return false ; } while (c < dot) { int tmp = ss[c++] - '0' ; if (tmp < 0 || tmp > 9 ) return false ; } } else { if (ss[c] == '+' || ss[c] == '-' ) ++c; if (c == dot) { if ((c++) + 1 == e) return false ; while (c < e) { int ttt = ss[c++] - '0' ; if (ttt < 0 || ttt > 9 ) return false ; } } else { while (c < dot) { int ttt = ss[c++] - '0' ; if (ttt < 0 || ttt > 9 ) return false ; } c = dot + 1 ; while (c < e) { int ttt = ss[c++] - '0' ; if (ttt < 0 || ttt > 9 ) return false ; } } } if (++e == n) return false ; if (e < n && (ss[e] == '+' || ss[e] == '-' )) { if (++e == n) return false ; } while (e < n) { int sss = ss[e++] - '0' ; if (sss < 0 || sss > 9 ) return false ; } return true ; } }
时间复杂度:\(O(n)\)
空间复杂度:\(O(1)\)
有限状态自动机
有限状态自动机(DFA)懂的也不是特别多,贴一下自己的做法供参考:
先列表写出所有状态,再对应写出转移到的状态,最后转化为代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 class DFA : def __init__ (self ) -> None : self .state = 0 self .end = [2 , 4 , 5 , 8 ] def get_char (self, s: str ) -> bool : num = ord (s) - ord ('0' ) if s in "+-" : if self .state == 0 : self .state = 1 elif self .state == 6 : self .state = 7 else : return False elif 0 <= num <= 9 : if self .state < 3 : self .state = 2 elif self .state < 6 : self .state = 5 elif self .state < 9 : self .state = 8 else : return False elif s in "eE" : if self .state == 2 or self .state == 4 or self .state == 5 : self .state = 6 else : return False elif s == '.' : if self .state < 2 : self .state = 3 elif self .state == 2 : self .state = 4 else : return False else : return False return True class Solution : def isNumber (self, s: str ) -> bool : dfa = DFA() for ss in s: if not dfa.get_char(ss): return False return dfa.state in dfa.end
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 class DFA {public : int state = 0 ; unordered_set<int > end{2 , 4 , 5 , 8 }; bool get_char (char s) { int num = s - '0' ; if (s == '+' || s == '-' ) { if (state == 0 ) state = 1 ; else if (state == 6 ) state = 7 ; else return false ; } else if (num >= 0 && num <= 9 ) { if (state < 3 ) state = 2 ; else if (state < 6 ) state = 5 ; else if (state < 9 ) state = 8 ; else return false ; } else if (s == 'e' || s == 'E' ) { if (state == 2 || state == 4 || state == 5 ) state = 6 ; else return false ; } else if (s == '.' ) { if (state < 2 ) state = 3 ; else if (state == 2 ) state = 4 ; else return false ; } else return false ; return true ; } }; class Solution {public : bool isNumber (string s) { DFA dfa; for (char ss : s) { if (!dfa.get_char (ss)) return false ; } return dfa.end.find (dfa.state) != dfa.end.end (); } };
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 class Solution { class DFA { public int state; public Set<Integer> end = new HashSet <>(10 ); public DFA () { state = 0 ; end.add(2 ); end.add(4 ); end.add(5 ); end.add(8 ); } public boolean get_char (char s) { int num = s - '0' ; if (s == '+' || s == '-' ) { if (state == 0 ) state = 1 ; else if (state == 6 ) state = 7 ; else return false ; } else if (num >= 0 && num <= 9 ) { if (state < 3 ) state = 2 ; else if (state < 6 ) state = 5 ; else if (state < 9 ) state = 8 ; else return false ; } else if (s == 'e' || s == 'E' ) { if (state == 2 || state == 4 || state == 5 ) state = 6 ; else return false ; } else if (s == '.' ) { if (state < 2 ) state = 3 ; else if (state == 2 ) state = 4 ; else return false ; } else return false ; return true ; } } public boolean isNumber (String s) { DFA dfa = new DFA (); char [] st = s.toCharArray(); for (char ss : st) { if (!dfa.get_char(ss)) return false ; } return dfa.end.contains(dfa.state); } }
时间复杂度:\(O(n)\)
空间复杂度:\(O(1)\)
最后再补充两个类型相似的题目,学会了的话可以去练练手哦~
8. 字符串转换整数
(atoi) 393. UTF-8
编码验证