0%

剑指Offer 面试题20 表示数值的字符串

剑指Offer 面试题20 表示数值的字符串

题目说明:

剑指 Offer 20. 表示数值的字符串

中等

请实现一个函数用来判断字符串是否表示数值(包括整数和小数)。例如,字符串"+100"、"5e2"、"-123"、"3.1416"、"-1E-16"、"0123"都表示数值,但"12e"、"1a3.14"、"1.2.3"、"+-5"及"12e+5.4"都不是。

解题思路:

之前跟着 [@Milo Yip](https://github.com/miloyip) 的 开源项目 实现过基于C的JSON解析,所以这题做着还蛮开心。

解析字符串表示的数字,关键在于划分数字的不同部分,以及各个部分是不是一定要出现,每一部分我们都通过起始字符来判断。

首先在LeetCode评论区 @上弦月 列出的部分测试样例中挑选了几个正确但较反常识的样例:

1
2
3
4
"1 "
".1"
" 0"
"3."

从这些样例中可以看出如下两个易错的部分:

  1. 首尾允许存在空格;
  2. 整数及小数部分只要小数点某一侧有数字即可归为合法;

分部解析思路:

  1. 跳过字符串首尾的空白部分;

  2. 如果有,则跳过 + / - 符号部分;

  3. 接下来是测试样例比较讨厌的整数及小数部分;

    样例中这一部分共4种情况 ①只有整数 ②整数 + '.' ③整数 + '.' + 小数 ④'.' + 小数;我们通过判断这一部分起始位置的字符来分别解析;

    1. 0~9 的数字为起始

      ①首先使用 while 跳过整数部分连续的数字,因为允许首0存在,所以不需要判断首个数字是不是0;

      ②接下来判断有没有小数点,若有则跳过小数点,并使用同样的方法跳过后续的小数部分,因为这种情况下确定了整数部分是有数字的,所以小数部分不需要至少一位小数;

    2. '.' 小数点为起始

      ①跳过 '.'

      ②因为整数部分没有数字,所以小数部分至少要有一位小数,添加一个强制判断;

      ③跳过全部的数字部分;

  4. 指数部分;

    ①首先判断下一位字符是不是 eE,若是则进入指数部分的判断;

    ②判断正负号,有则跳过;

    ③指数的数字部分也至少需要一位数,添加一个类似小数部分的强制判断;

    ④跳过所有连续的数字;

  5. 跳过末尾空白

  6. 以上部分按顺序判断完成后,若字符串符合标准,迭代器或指针应该已经走到了字符串的末尾,判断一下是否走到末尾即可判定该字符串是否表示数值。

代码:

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
bool isNumber(string s) {
auto iter = s.begin();
// whitespace
while (*iter == ' ')
++iter;
// sign part
if (*iter == '+' || *iter == '-')
++iter;

// integer & decimal part
if ((*iter < '0' || *iter > '9') && *iter != '.')
return false;
// start with integer
if (*iter >= '0' && *iter <= '9') {
while (*iter >= '0' && *iter <= '9')
++iter;
// decimal part
if (*iter == '.') {
++iter;
while (*iter >= '0' && *iter <= '9')
++iter;
}
}
// start with decimal point
else {
++iter;
if (*iter < '0' || *iter > '9')
return false;
while (*iter >= '0' && *iter <= '9')
++iter;
}

// exponent part
if (*iter == 'e' || *iter == 'E') {
++iter;
if (*iter == '+' || *iter == '-')
++iter;
if (*iter < '0' || *iter > '9')
return false;
while (*iter >= '0' && *iter <= '9')
++iter;
}

// whitespace
while (*iter == ' ')
++iter;

return iter == s.end();
}