最近打算换工作,为了准备面试,不得不预习数据结构与算法,想了想还是刷题吧。。
言归正传,字符串转整数,核心思想非常简单,就是根据字符'0'到'9'的整型值是连续的,所以嘛只要把字符转换成整数值,再减去'0'字符的值,就能对应得到其十进制值了。也就是说:
int charValue = myChar - '0';
如果字符是'0'到'9',那么通过上述方法得到的字符整数值就是对应的0到9;如果字符是非数字值,那么得到的结果肯定就小于0或者大于9了。
解决了一个字符转换成整数,那么一个完整的字符串呢,就需要通过遍历得到每一个字符,转换成整数后再乘以其对应的权值就行了,也就是乘以10,最后求和,代码如下:
for(int i=0;i< str.length();i++){
int charValue = str.charAt(i) - '0';
sum = sum * 10 + charValue;
}
那么核心思想就是这么简单。但是如果你把这个直接提交到LeetCode,就会出错。因为这段代码不够健壮,许多情况都没有考虑,在某些条件下程序会报错。这也就是我写这篇文章的原因了,把要点记录下来,并最后附上源码,直接提交到LeetCode没有任何问题。
接下来分析保证算法健壮的方法:
- 保证输入的字符串是非空的。如果是null,那就不需要继续往下走了,直接返回0;
- 考虑字符串开头有一堆空格的情况。字符串可以包含非数字字符,但是程序必须能够检测到这些字符并加以处理。在这里,如果字符串开头有空格,那么就跳过这些空格,找到第一个非空格的字符;
- 字符串开头可以有正号或者是负号。“+”和“-”字符用来表示数字是正还是负,这无可厚非,程序应该能够容忍这两个字符,但是只能容忍一次。也就是说如果遇到“++”、“+-”、“-+”、“++-”……等等这些字符串的时候,程序应该说NO,并返回0;
- 字符串中可能包含其他字符。如果跳过空格了,也跳过正号或者负号了,程序希望接下来的字符必须以数字字符开始。这样的字符串“ +123”、“ +123h1”、“ -123+32”等等,都是可以接受的,返回123或者-123。但是“ +h12j”、“ +-13”等等这样的字符就不能容忍了,返回0;
- 考虑数值边界问题。如果字符串通过了上面4种情况的考核,那么就可以愉快的将它转换成数字了。但是这个时候又有一个陷阱,比如算法的返回值是int类型的,int类型的数据存在一个能表示的最大值和最小值,可以用Integer.MAX_VALUE和Integer.MIN_VALUE得到,比如最大值是2147483647,只能表示10位,当字符串是"9999999999"(10个9)的时候,程序执行到第9个9的时候就应该提高警惕,因为这时如果再增加一位,必然会导致溢出。特殊情况下考虑,"2147483648"这样的字符串,前9位都没有问题,但是第10位的数字是8,终究还是大了一位,可惜啊,程序只能返回2147483647。
如果考虑完上面所有情况,写出来的代码提交到LeetCode就没有问题了。不过还是挺费精力的,我是无法一下子就考虑完备,一边提交出错修改再提交再出错,最后才修改完善的。最后附上完整源码:
class Solution {
public int myAtoi(String str) {
int index = 0;//字符串中字符的索引
int sum = 0;//最后的求和结果
int factor = 1;//系数代表正和负
int charValue = 0;//字符串中单个字符转换成的整数值
//边界
int max = Integer.MAX_VALUE;
int min = Integer.MIN_VALUE;
if(str.length() == 0){
return 0;
}
//忽略开头的多个空格
for(int i=0;i < str.length();i++){
if(str.charAt(index) == ' '){
index++;
}else{
break;
}
}
//开头可以有一个‘+’或者‘-’
//注意index每一次加一后,都有可能out of range
if(index >= str.length()){
return 0;
}else if(str.charAt(index) == '-'){
factor = -1;//-1代表负号
index++;
}else if(str.charAt(index) == '+'){
index++;
}
for(;index < str.length();index++){
charValue = str.charAt(index) - '0';
// 跳过正负号后字符串开头不能再有非数字字符,但是后面可跟非数字字符
if(charValue < 0 || charValue > 9){
break;
}
// 越界处理
if(max/10 < sum){
return (factor == 1) ? max : min;
}else if(max/10 == sum){
if(charValue > 7){
return (factor == 1) ? max : min;
}else{
sum = sum * 10 + charValue;
}
}else{
sum = sum * 10 + charValue;
}
}
return factor * sum;
}
}