20. 表示数值的字符串
1. 问题
请实现一个函数用来判断字符串是否表示数值(包括整数和小数)。例如,字符串"+100"、"5e2"、"-123"、"3.1416"、"-1E-16"、"0123"都表示数值,但"12e"、"1a3.14"、"1.2.3"、"+-5"及"12e+5.4"都不是。
2. 解法
这个方法还是不太行,去看看 LEETCODE 08,那一题会做就行了,题解看甜姨的。
2.1 Java
class Solution {
// 全局索引
public int index = 0;
public boolean isNumber(String s) {
// 假设字符串的形式为A.BeC或者A.BEC
// A为整数部分,B为小数部分,C为指数部分,按顺序判断是否包含这三个部分
// 1. 在字符串最后添加结束标记
// 2. 使用全局索引index遍历字符串
// 3. scanInteger扫描有符号整数,用于匹配A和C
// 4. scanUnsignedInteger扫描无符号整数,用于匹配B
// 另外需要注意字符串首尾若有空格是合法的
// 特判
if (s == null || s.length() == 0)
return false;
// 字符串s是否是一个数字
boolean isNum = false;
// Step1: 添加结束标志
s += '*';
// Step2: 跳过字符串首部的所有空格(如果存在的话)
while (s.charAt(index) == ' ')
index++;
// Step3: 整数部分
isNum = scanInteger(s);
// Step4. 小数部分(如果存在小数点的话)
if (s.charAt(index) == '.') {
// 跳过小数点
index++;
// 处理小数部分,小数点左右两边只要有一边有数字就合法,所以使用「 || 」
isNum = scanUnsignedInteger(s) || isNum;
}
// Step5. 指数部分(如果存在e或E的话)
if (s.charAt(index) == 'E' || s.charAt(index) == 'e') {
// 跳过E或e
index++;
// 处理指数部分,e或E的两边都必须有数字,所以使用「 && 」
isNum = scanInteger(s) && isNum;
}
// Step6. 跳过字符串尾部的所有空格(如果存在的话)
while (s.charAt(index) == ' ')
index++;
// Step7. 看是否遍历到了字符串最后,如果没有到最后的话,一定不是一个数字
// 如果遍历到了最后且isNum为true,那么s就是一个数字
isNum = isNum && s.charAt(index) == '*';
return isNum;
}
// 扫描无符号整数,用于匹配B(小数部分)
// 判断字符串内是否包含无符号数
public boolean scanUnsignedInteger(String str) {
// 记下最开始的位置
int start = index;
// 是数字就一直遍历下去
while(str.charAt(index) >= '0' && str.charAt(index) <= '9')
index++;
// 若index>start说明发现了无符号整数,否则说明不包含无符号整数
return index > start;
}
// 扫描有符号整数,用于匹配A(整数部分)和C(指数部分)
// 判断字符串内是否包含有符号整数
public boolean scanInteger(String str) {
// 如果是有符号的,跳过这个符号,然后把后面的字符串交给scanUnsignedInteger处理
if (str.charAt(index) == '+' || str.charAt(index) == '-')
index++;
return scanUnsignedInteger(str);
}
}
2.2 Kotlin
class Solution {
// 全局索引
var index = 0
fun isNumber(s: String?): Boolean {
var s = s
// 假设字符串的形式为A.BeC或者A.BEC
// A为整数部分,B为小数部分,C为指数部分,按顺序判断是否包含这三个部分
// 1. 在字符串最后添加结束标记
// 2. 使用全局索引index遍历字符串
// 3. scanInteger扫描有符号整数,用于匹配A和C
// 4. scanUnsignedInteger扫描无符号整数,用于匹配B
// 另外需要注意字符串首尾若有空格是合法的
// 特判
if (s == null || s.length == 0)
return false
// 字符串s是否是一个数字
var isNum = false
// Step1: 添加结束标志
s += '*'.toString()
// Step2: 跳过字符串首部的所有空格(如果存在的话)
while (s[index] == ' ')
index++
// Step3: 整数部分
isNum = scanInteger(s)
// Step4. 小数部分(如果存在小数点的话)
if (s[index] == '.') {
// 跳过小数点
index++
// 处理小数部分,小数点左右两边只要有一边有数字就合法,所以使用「 || 」
isNum = scanUnsignedInteger(s) || isNum
}
// Step5. 指数部分(如果存在e或E的话)
if (s[index] == 'E' || s[index] == 'e') {
// 跳过E或e
index++
// 处理指数部分,e或E的两边都必须有数字,所以使用「 && 」
isNum = scanInteger(s) && isNum
}
// Step6. 跳过字符串尾部的所有空格(如果存在的话)
while (s[index] == ' ')
index++
// Step7. 看是否遍历到了字符串最后,如果没有到最后的话,一定不是一个数字
// 如果遍历到了最后且isNum为true,那么s就是一个数字
isNum = isNum && s[index] == '*'
return isNum
}
// 扫描无符号整数,用于匹配B(小数部分)
// 判断字符串内是否包含无符号数
fun scanUnsignedInteger(str: String): Boolean {
// 记下最开始的位置
val start = index
// 是数字就一直遍历下去
while (str[index] >= '0' && str[index] <= '9')
index++
// 若index>start说明发现了无符号整数,否则说明不包含无符号整数
return index > start
}
// 扫描有符号整数,用于匹配A(整数部分)和C(指数部分)
// 判断字符串内是否包含有符号整数
fun scanInteger(str: String): Boolean {
// 如果是有符号的,跳过这个符号,然后把后面的字符串交给scanUnsignedInteger处理
if (str[index] == '+' || str[index] == '-')
index++
return scanUnsignedInteger(str)
}
}
还有个解法是用有限状态自动机来做的,直接看K佬的题解吧,我看着就头晕OTZ。#就是不想做
2.3 LEETCODE-08 解法
字符串转数字 🔢
res * 10 + num > Integer.MAX_VALUE 需要注意,直接这么写会越界的,稍微移动一下就不会出现越界的情况了。
class Solution {
public int myAtoi(String str) {
//先去除前置的所有空格
int index = 0;
int length = str.length();
char[] ch = str.toCharArray();
while(index<length && ch[index]==' '){
index++;
}
//去除空格后如果到了末尾,直接返回0
if(index==length){
return 0;
}
//判断是否为负数
boolean isNeg = false;
if(ch[index]=='-'){
isNeg = true;
index++;
}else if(ch[index]=='+'){
index++;
}
// 最终结果
int res = 0;
//当字符为数字时进行累加
while(index<length && isNum(ch[index])){
int num = ch[index] - '0';
// 为了防止越界,将 res * 10 + num > Integer.MAX_VALUE 不等式移动了一下
// 如果已经比最大值还要大了,就看是负数还是正数
// 负数返回Integer.MIN_VALUE,正数返回Integer.MAX_VALUE
if(res > (Integer.MAX_VALUE - num) / 10){
return isNeg ? Integer.MIN_VALUE : Integer.MAX_VALUE;
}
// 累加
res = res*10+num;
// 索引右移
index++;
}
// 返回结果
return isNeg ? -res : res;
}
public boolean isNum(char c){
if(c>='0'&&c<='9'){
return true;
}else{
return false;
}
}
}
3. 参考
最后更新于