Skip to content

Latest commit

 

History

History
225 lines (202 loc) · 7.54 KB

20.表示数值的字符串.md

File metadata and controls

225 lines (202 loc) · 7.54 KB

20.表达数值的字符串

题目描述

请实现一个函数用来判断字符串str是否表示数值(包括科学计数法的数字,小数和整数)。

科学计数法的数字(按顺序)可以分成以下几个部分:

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

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

  • 1.若干空格
  • 2.(可选)一个符号字符('+' 或 '-')
    1. 可能是以下描述格式之一:
    • 3.1 至少一位数字,后面跟着一个点 '.'
    • 3.2 至少一位数字,后面跟着一个点 '.' ,后面再跟着至少一位数字
    • 3.3 一个点 '.' ,后面跟着至少一位数字
  • 4.若干空格

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

  • 1.若干空格
  • 2.(可选)一个符号字符('+' 或 '-')
    1. 至少一位数字
  • 4.若干空格

例如,字符串["+100","5e2","-123","3.1416","-1E-16"]都表示数值。 但是["12e","1a3.14","1.2.3","+-5","12e+4.3"]都不是数值。

提示:

  • 1.1 <= str.length <= 25
  • 2.str 仅含英文字母(大写和小写),数字(0-9),加号 '+' ,减号 '-' ,空格 ' ' 或者点 '.' 。
  • 3.如果怀疑用例是不是能表示为数值的,可以使用pythonprint(float(str))去查看

示例1

输入:"123.45e+6"
返回值:true

示例2

输入:"1.2.3"
返回值:false

思路 & 解答

这道题咋一看,有点复杂,case很多,主要是分析好判断分支,我们可以定义几个变量:

  • hashNum: 是否已经有数字
  • hashE:是否已经有E
  • hasSign:是否已经有符号
  • hasDot:是否已经有小数点

首先,初始化当前的索引index =0,字符串头部的空格需要跳过。

  • 循环判断索引是否在有效的范围内:
    • 循环判断是否是数字,是数字则更新hasNum = true,并且索引后移,直到不是数字的时候,跳出循环。
  • 跳出循环后,需要判断当前的index是否合法,不合法直接break
  • 取出当前索引的字符c
    • 如果ce或者E
      • 如果前面已经出现过E,或者前面没有数字,直接返回false
      • 否则,hasE置为true,其他的置为false,也就是E后面可以继续出现符号数字和小数点了
    • 如果c是“+”或者“-”:
      • 前面如果已经出现过数字或者符号或者小数点,都不是合法的
      • 否则hasSign置为true,表示符号出现过
    • 如果c是小数点“.
      • 如果前面已经有小数点或者有E出现了,那么就是非法的,返回false
      • 否则hasDot置为true
    • 如果c为空格,直接跳出循环
    • 否则,直接返回false
  • 最后也需要跳过空格
  • 最后判断是否合法的条件是:是否到达最后一个字符,并且出现过数字
    public boolean isNumeric(String str) {
        int size = str.length();
        int index= 0 ;
        // 默认全部是false
        boolean hashNum=false ,hasE=false ,hasSign=false ,hasDot=false;
        // 跳过空格
        while(index<size&&str.charAt(index)==' '){
            index++;
        }
        while(index<size){
            while(index<size&&str.charAt(index)>='0'&& str.charAt(index)<='9'){
                index++;
                // 表示前面有数字
                hashNum = true;
            }
            // 到末尾直接跳出
            if(index==size){
                break;
            }
            char c = str.charAt(index);
            if(c=='e'||c=='E'){
                // 前面有E或者没有数字在前面
                if(hasE||!hashNum){
                    return false;
                }
                hasE = true;
                // 出现E了后面又可以出现数字了
                hashNum = false;
                hasSign = false;
                hasDot = false;
            }else if(c=='+'||c=='-'){
                if(hasSign||hashNum||hasDot){
                    return false;
                }
                hasSign = true;
            }else if(c=='.'){
                if(hasDot||hasE){
                    return false;
                }
                hasDot =true;
            }else if(c==' '){
                break;
            }else{
                return false;
            }
            index++;
        }        
        // 跳过空格
        while(index<size&&str.charAt(index)==' '){
            index++;
        }
        return hashNum &&index==size;
    }

C++代码如下:

class Solution {
public:
    bool isNumeric(string str) {
        int size = str.length();
        int index = 0;
        // 默认全部是false
        bool hashNum = false, hasE = false, hasSign = false, hasDot = false;
        // 跳过空格
        while (index < size && str[index] == ' ') {
            index++;
        }
        while (index < size) {
            while (index < size && str[index] >= '0' && str[index] <= '9') {
                index++;
                // 表示前面有数字
                hashNum = true;
            }
            // 到末尾直接跳出
            if (index == size) {
                break;
            }
            char c = str[index];
            if (c == 'e' || c == 'E') {
                // 前面有E或者没有数字在前面
                if (hasE || !hashNum) {
                    return false;
                }
                hasE = true;
                // 出现E了后面又可以出现数字了
                hashNum = false;
                hasSign = false;
                hasDot = false;
            } else if (c == '+' || c == '-') {
                if (hasSign || hashNum || hasDot) {
                    return false;
                }
                hasSign = true;
            } else if (c == '.') {
                if (hasDot || hasE) {
                    return false;
                }
                hasDot = true;
            } else if (c == ' ') {
                break;
            } else {
                return false;
            }
            index++;
        }
        // 跳过空格
        while (index < size && str[index] == ' ') {
            index++;
        }
        return hashNum && index == size;
    }
};

还有一种取巧的做法,那就是直接借助正则表达式进行匹配,这并非我自己想出来的,源于牛客网@Maokt,但是并不太推荐这种解法:

import java.util.*;
import java.util.regex.Pattern;

public class Solution {
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     * 
     * @param str string字符串 
     * @return bool布尔型
     */
    public boolean isNumeric (String str) {
        // write code here
        //        ^表示开头 $ 表示结尾  java中两个\\ 代表一个\
        //        * 零次或多次匹配前面的字符或子表达式
        //        ?零次或一次匹配前面的字符或子表达式
        //        + 一次或多次匹配前面的字符或子表达式
        //        [] 字符集。匹配包含的任一字符
        //        (:? )匹配 pattern 但不捕获该匹配的子表达式,即它是一个非捕获匹配
        String p = "^[+-]?(\\d*\\.\\d+|\\d+(\\.\\d*)?)(?:[eE][+-]?\\d+)?$";
        return Pattern.matches(p,str);
    }
}

总结一下

这道题,其实本质是状态的切换,最最重要的一点,是 E 出现之后,其实小数点和符号,和数字,都是可以再出现的,可以理解为 E 就是一个分割线。