Day26_字符与数字_剑指Offer
表示数值的字符串
medium 原题连接:表示数值的字符串
请实现一个函数用来判断字符串是否表示数值(包括整数和小数)。
数值(按顺序)可以分成以下几个部分:
若干空格
一个 小数 或者 整数
(可选)一个 ‘e’ 或 ‘E’ ,后面跟着一个 整数
若干空格
小数(按顺序)可以分成以下几个部分:
(可选)一个符号字符(’+’ 或 ‘-‘)
下述格式之一:
至少一位数字,后面跟着一个点 ‘.’
至少一位数字,后面跟着一个点 ‘.’ ,后面再跟着至少一位数字
一个点 ‘.’ ,后面跟着至少一位数字
整数(按顺序)
可以分成以下几个部分:
(可选)一个符号字符(’+’ 或 ‘-‘)至少一位数字
部分数值列举:[“+100”, “5e2”, “-123”, “3.1416”, “-1E-16”, “0123”]
部分非数值列举:[“12e”, “1a3.14”, “1.2.3”, “+-5”, “12e+5.4”]
示例:
输入:s = "0"
输出:true
输入:s = "e"
输出:false
输入:s = "."
输出:false
输入:s = " .1 "
输出:true
提示:
1 <= s.length <= 20
s
仅含英文字母(大写和小写),数字(0-9
),加号'+'
,减号'-'
,空格' '
或者点'.'
。
解题思路
一个包含全部可能的最大目标大致可以分为:
空格 正负 数字 小数点 数字 e/E 正负 数字 空格
从前到后依次划分部分进行检验:
- 删除前后空格
- 判断首字节是否为+-
- 依据E/e拆分为两个部分
- 前者判断是否由小数点,拆为两个部分
- 3中剩下的部分,4中的两个部分,检测是否为纯数字
注:允许4的前半部分为空
Java代码
class Solution {
public boolean isNumber(String s) {
// 空格 正负 数字 小数点 数字 e/E 正负 数字 空格
// 1.将s删去前后空格,判断charAt(0)是否是正负号
s = s.trim();
if(s.length() == 0) return false;
if(s.charAt(0) == '+' || s.charAt(0) == '-') s = s.substring(1);
// 2.将剩余string依据e/E划分为两个部分,如果第二部分长度不为零,判断charAt(0)是否为符号
s = s.replace('E','e');
if(s.indexOf('e') >= 0) {
int index = s.indexOf('e');
String firstStr = s.substring(0,index);
String secondStr = s.substring(index+1);
if(secondStr.length() > 0) {
if(secondStr.charAt(0) == '+' || secondStr.charAt(0) == '-') secondStr = secondStr.substring(1);
}
return isNum(firstStr) && isInteger(secondStr);
}
return isNum(s);
}
// 3.由2得到的两个字符,前者做数字判断(可为小数),后者做整数判断
// 判断是否为整数(不可以为小数)
public boolean isInteger(String str) {
if(str == "") return false;
for(char a : str.toCharArray()) {
if(a < '0' || a > '9') return false;
}
return true;
}
// 判断是否为数(可以为小数)
public boolean isNum(String str) {
if(str.indexOf('.') >= 0) {
int index = str.indexOf('.');
String firstStr = str.substring(0,index);
String secondStr = str.substring(index+1);
if(firstStr.length() >0 && secondStr.length() >0) {
return isInteger(firstStr) && isInteger(secondStr);
}else if(secondStr.length() >0) {
return isInteger(secondStr);
}else {
return isInteger(firstStr);
}
}
return isInteger(str);
}
}
把字符串转换成整数
medium 原题连接: 把字符串转换成整数
写一个函数 StrToInt,实现把字符串转换成整数这个功能。不能使用 atoi 或者其他类似的库函数。
首先,该函数会根据需要丢弃无用的开头空格字符,直到寻找到第一个非空格的字符为止。
当我们寻找到的第一个非空字符为正或者负号时,则将该符号与之后面尽可能多的连续数字组合起来,作为该整数的正负号;假如第一个非空字符是数字,则直接将其与之后连续的数字字符组合起来,形成整数。
该字符串除了有效的整数部分之后也可能会存在多余的字符,这些字符可以被忽略,它们对于函数不应该造成影响。
注意:假如该字符串中的第一个非空格字符不是一个有效整数字符、字符串为空或字符串仅包含空白字符时,则你的函数不需要进行转换。
在任何情况下,若函数不能进行有效的转换时,请返回 0。
说明:
假设我们的环境只能存储 32 位大小的有符号整数,那么其数值范围为 [−2^31, 2^31 − 1]。如果数值超过这个范围,请返回 INT_MAX (2^31 − 1) 或 INT_MIN (−2^31)
示例:
输入: "42"
输出: 42
输入: " -42"
输出: -42
解释: 第一个非空白字符为 '-', 它是一个负号。
我们尽可能将负号与后面所有连续出现的数字组合起来,最后得到 -42 。
输入: "4193 with words"
输出: 4193
输入: "words and 987"
输出: 0
解释: 第一个非空字符是 'w', 但它不是数字或正、负号。
因此无法执行有效的转换。
输入: "-91283472332"
输出: -2147483648
解释: 数字 "-91283472332" 超过 32 位有符号整数范围。
因此返回 INT_MIN (−231) 。
解题思路
和第一题有些类似,删除空格,判断符号,遇到字母就跳出
需要注意的是,如果第一个字符是符号,数字需要从下标为1的地方开始读,如果没有符号,则从0开始读
为了避免超过int类型的最大值,可以在循环中判断,是否即将超过最大值(因为每次记录结果是将ans= ans*10+new)
所以先判断是否依据超过了int最大值的十分之一(否则接下来进行*10运算会超过最大值)
又或者恰好为2147483648、 2147483649,刚好超过一两位,所以在ans已经相等于int最大值的十分之一时判断最后一位的值是否大于7
Java代码
class Solution {
public int strToInt(String str) {
// 1.删去str前后端的空格,并判断charAt(0)是否为符号,做记录(符号sign与数字开始位i)
str = str.trim();
if(str.length() == 0) return 0;
int sign = 1, index = 1;
if(str.charAt(0) == '-') {
sign = -1;
}else if(str.charAt(0) != '+'){
index = 0;
}
int ans = 0, max = Integer.MAX_VALUE/10;
// 2.循环对数每一位做判断:
for(; index < str.length(); index++) {
// 3.弹出条件之一:遇到不是数字的数,break
if(str.charAt(index)<'0' || str.charAt(index)>'9') break;
// 4.弹出条件之二:已经超过最大值(符号已经记录,单纯看数值大小)
if(ans>max || (ans==max && str.charAt(index)>'7'))
return sign == 1 ? Integer.MAX_VALUE : Integer.MIN_VALUE;
ans = ans*10+(str.charAt(index)-'0');
}
return ans*sign;
}
}