字符串题目:有效数字

本文介绍了一种无需使用正则表达式和有限状态自动机的方法来判断一个字符串是否为有效数字。文章详细阐述了解决方案的思路,并给出了具体实现的Java代码。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目

标题和出处

标题:有效数字

出处:65. 有效数字

难度

8 级

题目描述

要求

有效数字(按顺序)可以分成以下几个部分:

  1. 一个小数或者整数
  2. (可选)一个 ‘E’ \texttt{`E'} ‘E’ ‘e’ \texttt{`e'} ‘e’,后面跟着一个整数

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

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

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

  1. (可选)一个符号字符( ‘+’ \texttt{`+'} ‘+’ ‘-’ \texttt{`-'} ‘-’
  2. 至少一位数字

部分有效数字列举如下:

  • ["2",   "0089",   "-0.1",   "+3.14",   "4.",   "-.9",   "2e10",   "-90E3",   "3e+7",   "+6e-1",   "53.5e93",   "-123.456e789"] \texttt{["2", "0089", "-0.1", "+3.14", "4.", "-.9", "2e10", "-90E3", "3e+7", "+6e-1", "53.5e93", "-123.456e789"]} ["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"] \texttt{["abc", "1a", "1e", "e3", "99e2.5", "--6", "-+3", "95a54e53"]} ["abc", "1a", "1e", "e3", "99e2.5", "--6", "-+3", "95a54e53"]

给你一个字符串 s \texttt{s} s,如果 s \texttt{s} s 是一个有效数字,请返回 true \texttt{true} true

示例

示例 1:

输入: s   =   "0" \texttt{s = "0"} s = "0"
输出: true \texttt{true} true

示例 2:

输入: s   =   "e" \texttt{s = "e"} s = "e"
输出: false \texttt{false} false

示例 3:

输入: s   =   "." \texttt{s = "."} s = "."
输出: false \texttt{false} false

示例 4:

输入: s   =   ".1" \texttt{s = ".1"} s = ".1"
输出: true \texttt{true} true

数据范围

  • 1 ≤ s.length ≤ 20 \texttt{1} \le \texttt{s.length} \le \texttt{20} 1s.length20
  • s \texttt{s} s 仅含英语字母(大写和小写),数字( 0-9 \texttt{0-9} 0-9),加号 ‘+’ \texttt{`+'} ‘+’,减号 ‘-’ \texttt{`-'} ‘-’,或者点 ‘.’ \texttt{`.'} ‘.’

解法

思路和算法

这道题的解法有多种,包括正则表达式和有限状态自动机。此处提供的解法只需要遍历字符串即可,不使用正则表达式和有限状态自动机。

题目定义的小数和整数包含一个可选的符号字符,为了方便处理,将可选的符号字符分离,则小数只包含一位至多位数字和一个点,其中点可以位于任何位置,整数只包含一位至多位数字。

根据有效数字中是否有字母 ‘E’ \text{`E'} ‘E’ ‘e’ \text{`e'} ‘e’,可以分成两种情况。

  • 有效数字中没有字母,可以分成以下 2 2 2 个部分:
    1. (可选)一个符号字符( ‘+’ \text{`+'} ‘+’ ‘–’ \text{`--'} ‘–’);
    2. 一个小数或整数,包含一位至多位数字,最多包含一个点,点可以位于任何位置。
  • 有效数字中有字母,可以分成以下 5 5 5 个部分:
    1. (可选)一个符号字符( ‘+’ \text{`+'} ‘+’ ‘–’ \text{`--'} ‘–’);
    2. 一个小数或整数,包含一位至多位数字,最多包含一个点,点可以位于任何位置;
    3. 一个字母 ‘E’ \text{`E'} ‘E’ ‘e’ \text{`e'} ‘e’
    4. (可选)一个符号字符( ‘+’ \text{`+'} ‘+’ ‘–’ \text{`--'} ‘–’);
    5. 一个整数,包含一位至多位数字。

有字母和没有字母相比,多出了 3 3 3 个部分。前 2 2 2 个部分的处理逻辑相同,如果遇到字母,则继续处理后 3 3 3 个部分。

对于可选的第 1 1 1 部分,判断字符串 s s s 的第一个字符(即下标 0 0 0 的字符)是否为符号字符,如果是符号字符则跳过该字符。

对于第 2 2 2 部分,需要依次遍历每个字符,直到遍历到达字符串末尾或者遇到字母。对于遍历的每个字符,需要判断以下方面:

  • 每个字符必须是数字或者点,如果遇到符号字符则返回 false \text{false} false
  • 最多只能有一个字符是点,如果遇到两个字符是点则返回 false \text{false} false
  • 点的前面和后面的数字个数不能都是 0 0 0,对于整数的情况,将数字个数记为点的前面的数字个数,遍历结束之后,如果点的前面和后面的数字个数都是 0 0 0 则返回 false \text{false} false

在上述方面都满足的情况下,遍历结束第 2 2 2 部分之后,如果到达字符串末尾,则是没有字母的有效数字,返回 true \text{true} true

如果尚未到达字符串末尾,则当前字符一定是字母,如果当前字符是 ‘E’ \text{`E'} ‘E’ ‘e’ \text{`e'} ‘e’,则该字符为第 3 3 3 部分,否则当前字符不是有效数字的合法字符,返回 false \text{false} false

对于可选的第 4 4 4 部分,判断当前字符是否为符号字符,如果是符号字符则跳过该字符。

对于第 5 5 5 部分,需要依次遍历每个字符,直到遍历到达字符串末尾。必须至少有一个字符且每个字符必须都是数字,如果没有字符或者遇到非数字的字符则返回 false \text{false} false

到达字符串末尾时,如果每个部分的要求都满足,则是有字母的有效数字,返回 true \text{true} true

代码

class Solution {
    public boolean isNumber(String s) {
        int length = s.length();
        int index = 0;
        if (s.charAt(index) == '+' || s.charAt(index) == '-') {
            index++;
        }
        if (index == length) {
            return false;
        }
        int beforePoint = 0, afterPoint = 0;
        boolean point = false;
        while (index < length && !Character.isLetter(s.charAt(index))) {
            char c = s.charAt(index);
            if (c == '.') {
                if (!point) {
                    point = true;
                } else {
                    return false;
                }
            } else if (Character.isDigit(c)) {
                if (!point) {
                    beforePoint++;
                } else {
                    afterPoint++;
                }
            } else {
                return false;
            }
            index++;
        }
        if (beforePoint == 0 && afterPoint == 0) {
            return false;
        }
        if (index == length) {
            return true;
        }
        char letter = s.charAt(index);
        if (letter != 'E' && letter != 'e') {
            return false;
        }
        index++;
        if (index < length && (s.charAt(index) == '+' || s.charAt(index) == '-')) {
            index++;
        }
        if (index == length) {
            return false;
        }
        while (index < length) {
            if (!Character.isDigit(s.charAt(index))) {
                return false;
            }
            index++;
        }
        return true;
    }
}

复杂度分析

  • 时间复杂度: O ( n ) O(n) O(n),其中 n n n 是字符串 s s s 的长度。需要遍历字符串 s s s 一次,对于每个字符的判断时间都是 O ( 1 ) O(1) O(1)

  • 空间复杂度: O ( 1 ) O(1) O(1)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

伟大的车尔尼

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值