题目的主要信息:
  • 实现一个函数判断字符串是否表示数字
  • 包括科学记数法的数字:一个整数或小数,后接一个可选的大小写字母e,后接一个可正可负的整数
  • 小数,可选的正负号,小数点前后整数任意有一个即可
  • 整数,可选的正负号,加上后面的整数
  • 字符串可能包含前导、后导空格
举一反三:

学习完本题的思路你可以解决如下题目:

JZ67. 把字符串转换成整数(atoi)

方法一:遍历(推荐使用)

思路:

既然是字符串,那我们使用一个遍历字符串的全局变量作为下标,然后遍历字符串依次检查每个字符,根据字符属于的类型进行判断。

具体做法:

  • step 1:先判断空串的情况。
  • step 2:遍历字符前面的空格,将下标移到第一个不是空格的位置。遍历字符串后面的空格,将长度限制在最后一个空格。若是长度小于下标,说明全是空格。
  • step 3:剩余部分判断,开始找数字,判断是不是一个有符号的整数,优先判断符号,直到遇到非数字停止。
  • step 4:如果有小数点,那么开始判断小数点后是不是一个无符号的整数,也是遍历直到遇到非数字为止,出现小数点的话,小数点前和小数点后的数字任意有一即可。
  • step 5:若是出现字母e或者E,那么需要判断后面是不是一个有符号的整数,,也是遍历直到遇到非数字为止,e前后都要数字。
  • step 6:最后检查下标是不是遍历到了刚刚限制的长度,若是没有,说明后面还有非空格,不符合要求。

图示:

alt

Java实现代码:

import java.util.*;
public class Solution {
    //遍历字符串的下标
    private int index = 0;
    //有符号判断
    private boolean integer(String s){
        if(index < s.length() && (s.charAt(index) == '-' || s.charAt(index) == '+'))
            index++;
        return unsigned_integer(s);
    }
    //无符号数判断
    private boolean unsigned_integer(String s){
        int temp = index;
        while(index < s.length() && (s.charAt(index) >= '0' && s.charAt(index) <= '9'))
            index++;
        return index > temp;
    }
    public boolean isNumeric (String str) {
        //先判断空串
        if(str == null || str.length() == 0)
            return false;
        //去除前面的空格
        while(index < str.length() && str.charAt(index) == ' ')
            index++;
        int n = str.length() - 1;
        //去除字符串后面的空格
        while(n >= 0 && str.charAt(n) == ' ')
            n--;
        //限制的长度比下标1
        n++;
        //全是空格情况
        if(n < index)
            return false;
        //判断前面的字符是否是有符号的整数
        boolean flag = integer(str);
        //如果有小数点
        if(index < n && str.charAt(index) == '.'){
            index++;
            //小数点前后有无数字可选
            flag = unsigned_integer(str) || flag; 
        }
        //如果有e
        if(index < n && (str.charAt(index) == 'e' || str.charAt(index) == 'E')){
            index++;
            //e后面必须全是整数
            flag = flag && integer(str);
        }
        //是否字符串遍历结束
        return flag && (index == n);
    }
}

C++实现代码:

class Solution {
public:
    //遍历字符串的下标
    int index = 0;
    //有符号判断
    bool integer(string& s){
        if(index < s.length() && (s[index] == '-' || s[index] == '+'))
            index++;
        return unsigned_integer(s);
    }
    //无符号数判断
    bool unsigned_integer(string& s){
        int temp = index;
        while(index < s.length() && (s[index] >= '0' && s[index] <= '9'))
            index++;
        return index > temp;
    }
    bool isNumeric(string str) {
        //先判断空串
        if(str.length() == 0)
            return false;
        //去除前面的空格
        while(index < str.length() && str[index] == ' ')
            index++;
        int n = str.length() - 1;
        //去除字符串后面的空格
        while(n >= 0 && str[n] == ' ')
            n--;
        //限制的长度比下标1
        n++;
        //全是空格情况
        if(n < index)
            return false;
        //判断前面的字符是否是有符号的整数
        bool flag = integer(str);
        //如果有小数点
        if(index < n && str[index] == '.'){
            index++;
            //小数点前后有无数字可选
            flag = unsigned_integer(str) || flag; 
        }
        //如果有e
        if(index < n && (str[index] == 'e' || str[index] == 'E')){
            index++;
            //e后面必须全是整数
            flag = flag && integer(str);
        }
        //是否字符串遍历结束
        return flag && (index == n);
    }
};

Python实现代码:

class Solution:
    def __init__(self):
        #遍历字符串的下标
        self.index = 0
    #有符号判断
    def integer(self, s: str) -> bool:
        if self.index < len(s) and (s[self.index] == '-' or s[self.index] == '+'):
            self.index += 1
        return self.unsigned_integer(s)
    #无符号数判断
    def unsigned_integer(self, s: str) -> bool:
        temp = self.index
        while self.index < len(s) and (s[self.index] >= '0' and s[self.index] <= '9'):
            self.index += 1
        return self.index > temp
    
    def isNumeric(self , str: str) -> bool:
        #先判断空串
        if len(str) == 0:
            return False
        #去除前面的空格
        while self.index < len(str) and str[self.index] == ' ':
            self.index += 1
        n = len(str) - 1
        #去除字符串后面的空格
        while n >= 0 and str[n] == ' ':
            n -= 1
        #限制的长度比下标1
        n += 1
        #全是空格情况
        if n < self.index:
            return False
        #判断前面的字符是否是有符号的整数
        flag = self.integer(str)
        #如果有小数点
        if self.index < n and str[self.index] == '.':
            self.index += 1
            #小数点前后有无数字可选
            flag = self.unsigned_integer(str) or flag
        #如果有e
        if self.index < n and (str[self.index] == 'e' or str[self.index] == 'E'):
            self.index += 1
            #e后面必须全是整数
            flag = flag and self.integer(str)
        #是否字符串遍历结束
        return flag and (self.index == n)

复杂度分析:

  • 时间复杂度:O(n)O(n),其中nn为字符串长度,最坏遍历字符串每个字符一次
  • 空间复杂度:O(1)O(1),常数级变量,无额外辅助空间
方法二:正则表达式(扩展思路)

思路:

可以使用正则表示匹配直接匹配字符串是否表示数字。其中C++和Java中使用双斜杠,Python使用单斜杠。

具体做法:

  • step 1:用\s表示匹配空格,*表示匹配0个或多个,写在正则表达式首尾。
  • step 2:正负号可选,因此使用?匹配正负号。
  • step 3:整数用\d匹配,小数点前有无数字可以用|表示:小数点前有数字,匹配小数点,后面的数字可有可无;小数前没有数字,匹配小数点后必须有数字。
  • step 4:匹配大小写字母[Ee],以及后面可有可无的正负号,后面必须匹配一个整数。

Java实现代码:

import java.util.regex.Pattern;
public class Solution {

    public boolean isNumeric (String str) {
       //正则表达式匹配
        String pattern = "(\\s)*[+-]?((\\d+(\\.(\\d+)?)?)|(\\.\\d+))([Ee][+-]?\\d+)?(\\s)*";
        //根据匹配值返回
        return Pattern.matches(pattern, str);
    }
}

C++实现代码:

#include<regex>
class Solution {
public:
    bool isNumeric(string str) {
        //正则表达式匹配
        string pattern = "(\\s)*[+-]?((\\d+(\\.(\\d+)?)?)|(\\.\\d+))([Ee][+-]?\\d+)?(\\s)*";
        regex re(pattern);
        //根据匹配值返回
        return regex_match(str, re);
    }
};

Python实现代码:

import re
class Solution:
    def isNumeric(self , str: str) -> bool:
        #正则表达式匹配
        pattern = "^(\s)*[+-]?((\d+(\.(\d+)?)?)|(\.\d+))([Ee][+-]?\d+)?(\s)*$"
        #根据匹配值返回
        if re.match(pattern, str):
            return True
        else:
            return False

复杂度分析:

  • 时间复杂度:O(n)O(n),其中nn为字符串长度,正则表达式最坏遍历每个字符一次
  • 空间复杂度:O(1)O(1),常数级空间