Skip to content

Latest commit

 

History

History
116 lines (86 loc) · 3.9 KB

20-表示数值的字符串~Medium.md

File metadata and controls

116 lines (86 loc) · 3.9 KB

表示数值的字符串

请实现一个函数用来判断字符串是否表示数值(包括整数和小数)。

数值(按顺序)可以分成以下几个部分:

  1. 若干空格
  2. 一个小数或者整数
  3. (可选)一个 'e' 或 'E',后面跟着一个整数
  4. 若干空格

小数(按顺序)可以分成以下几个部分:

  1. (可选)一个符号字符('+' 或 '-')
  2. 下述格式之一: 1. 至少一位数字,后面跟着一个点 '.' 2. 至少一位数字,后面跟着一个点 '.' ,后面再跟着至少一位数字 3. 一个点 '.' ,后面跟着至少一位数字

整数(按顺序)可以分成以下几个部分:

  1. (可选)一个符号字符('+' 或 '-')
  2. 至少一位数字

部分数值列举如下:

["+100", "5e2", "-123", "3.1416", "-1E-16", "0123"]

部分非数值列举如下:

["12e", "1a3.14", "1.2.3", "+-5", "12e+5.4"]

示例 1:

输入:s = "0" 输出:true

示例 2:

输入:s = "e" 输出:false

示例 3:

输入:s = "." 输出:false

示例 4:

输入:s = ".1" 输出:true

提示:

  • 1 <= s.length <= 20
  • s 仅含英文字母(大写和小写),数字(0-9),加号 '+' ,减号 '-' ,空格 ' ' 或者点 '.' 。

思路:

排除所有错误情况 逻辑上没怎么考算法,所以算法方面没难度,难点在于归纳各种正确的情况

  1. . 出现正确情况:只出现一次(即前面没出现过),且出现在 e 或 E 的前面

    • 因为如果前面出现过 e/E 再出现. 说明 e/E 后面跟着小数,不符合题意
  2. eE 出现正确情况:只出现一次(即前面没出现过),且出现前有数字,出现后后面也得有数字

  3. +、- 出现正确情况:只能在开头 和 e 或 E 的后一位

解题思路:

  • 返回值:通过判断 numFlag 是否为 true 来判断字符串符不符合
    • 首先通过不断遍历过程中,如果有不符合上面三点情况的话,直接会返回 false
    • 如果遍历完还没发现代码有什么问题,不能掉以轻心,因为此时来到了最后一个特殊情况,即 123e 或 123E
      • 因为 e/E 后面必须还得有数字,所以可以在遍历过程中看 e/E 后面是否直接跟着数字 或 出现正负号后还有没有跟着数字,比较繁琐
      • 因此我直接选择判断 numFlag 是否等于 true,来判断 e/E 后面还有没有出现过数字
      • 方法:在出现 e/E 后,将 numFlag 变为 false,如果后面有数字那就自然而然 numFlag 又变为 true
function isNumber(s: string): boolean {
  let i: number,
    len: number,
    numFlag:boolean = false,
    dotFlag:boolean = false,
    eFlag:boolean = false;
  s = s.trim(); // 去掉首尾空格
  len = s.length; // 去掉后再重新计算长度
  for (i = 0; i < len; i++) {
    // 如果是数字,那么直接将 numFlag 变为 true 即可
    if (s[i] >= '0' && s[i] <= '9') {
      numFlag = true;
    } else if (s[i] === '.' && !dotFlag && !eFlag) {
      // 如果是 .  那必须前面还出现过 .  且前面没出现过 e/E,因为如果前面出现过 e/E 再出现. 说明 e/E 后面跟着小数,不符合题意
      dotFlag = true;
    } else if ((s[i] === 'e' || s[i] === 'E') && !eFlag && numFlag) {
      // 如果是 e 或 E,那必须前面没出现过 e/E,且前面出现过数字
      eFlag = true;
      numFlag = false; // 这一步很重要,将是否出现过数字的 Flag 置为 false,防止出现 123E 这种情况,即出现 e/E 后,后面没数字了
    } else if (
      (s[i] === '+' || s[i] === '-') &&
      (i === 0 || s[i - 1] === 'e' || s[i - 1] === 'E')
    ) {
      // 如果是 +/- 那必须是在第一位,或是在 e/E 的后面
    } else {
      // 上面情况都不满足,直接返回 false 即可,提前剪枝
      return false;
    }
  }
  return numFlag;
}