Skip to content

Latest commit

 

History

History
250 lines (203 loc) · 8.21 KB

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

File metadata and controls

250 lines (203 loc) · 8.21 KB

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

题目

请你来实现一个 myAtoi(string s) 函数,使其能将字符串转换成一个 32 位有符号整数(类似 C/C++ 中的 atoi 函数)。

函数 myAtoi(string s) 的算法如下:

读入字符串并丢弃无用的前导空格 检查下一个字符(假设还未到字符末尾)为正还是负号,读取该字符(如果有)。 确定最终结果是负数还是正数。 如果两者都不存在,则假定结果为正。 读入下一个字符,直到到达下一个非数字字符或到达输入的结尾。字符串的其余部分将被忽略。 将前面步骤读入的这些数字转换为整数(即,"123" -> 123, "0032" -> 32)。如果没有读入数字,则整数为 0 。必要时更改符号(从步骤 2 开始)。 如果整数数超过 32 位有符号整数范围 [−231, 231 − 1] ,需要截断这个整数,使其保持在这个范围内。具体来说,小于 −231 的整数应该被固定为 −231 ,大于 231 − 1 的整数应该被固定为 231 − 1 。 返回整数作为最终结果。 注意:

  • 本题中的空白字符只包括空格字符 ' ' 。
  • 除前导空格或数字后的其余字符串外,请勿忽略 任何其他字符。

示例 1:

输入:s = "42"
输出:42
解释:加粗的字符串为已经读入的字符,插入符号是当前读取的字符。
第 1 步:"42"(当前没有读入字符,因为没有前导空格)
         ^
第 2 步:"42"(当前没有读入字符,因为这里不存在 '-' 或者 '+')
         ^
第 3 步:"42"(读入 "42")
           ^
解析得到整数 42 。
由于 "42" 在范围 [-231, 231 - 1] 内,最终结果为 42 。

示例 2:

输入:s = "   -42"
输出:-42
解释:
第 1 步:"   -42"(读入前导空格,但忽视掉)
            ^
第 2 步:"   -42"(读入 '-' 字符,所以结果应该是负数)
             ^
第 3 步:"   -42"(读入 "42")
               ^
解析得到整数 -42 。
由于 "-42" 在范围 [-231, 231 - 1] 内,最终结果为 -42 。

示例 3:

输入:s = "4193 with words"
输出:4193
解释:
第 1 步:"4193 with words"(当前没有读入字符,因为没有前导空格)
         ^
第 2 步:"4193 with words"(当前没有读入字符,因为这里不存在 '-' 或者 '+')
         ^
第 3 步:"4193 with words"(读入 "4193";由于下一个字符不是一个数字,所以读入停止)
             ^
解析得到整数 4193 。
由于 "4193" 在范围 [-231, 231 - 1] 内,最终结果为 4193 。

示例 4:

输入:s = "words and 987"
输出:0
解释:
第 1 步:"words and 987"(当前没有读入字符,因为没有前导空格)
         ^
第 2 步:"words and 987"(当前没有读入字符,因为这里不存在 '-' 或者 '+')
         ^
第 3 步:"words and 987"(由于当前字符 'w' 不是一个数字,所以读入停止)
         ^
解析得到整数 0 ,因为没有读入任何数字。
由于 0 在范围 [-231, 231 - 1] 内,最终结果为 0 。

示例 5:

输入:s = "-91283472332"
输出:-2147483648
解释:
第 1 步:"-91283472332"(当前没有读入字符,因为没有前导空格)
         ^
第 2 步:"-91283472332"(读入 '-' 字符,所以结果应该是负数)
          ^
第 3 步:"-91283472332"(读入 "91283472332")
                     ^
解析得到整数 -91283472332 。
由于 -91283472332 小于范围 [-231, 231 - 1] 的下界,最终结果被截断为 -231 = -2147483648 。

提示:

0 <= s.length <= 200 s 由英文字母(大写和小写)、数字(0-9)、' '、'+'、'-' 和 '.' 组成

思路与解答

这道题目看起来很长,但是实际上逻辑很清晰,就是将字符串解析成为数字,里面有几个特殊的规则:

  • 1.前面的空格去掉,不读取
  • 2.接下来的字符必须是数字,“+”号或者“-”号
    • 2.1 如果是“+”号或者“-”号,将符号记录下来
    • 2.2 没有符号默认是“+”号,正数。
  • 3.接下来的字符必须是数字,遇到其他字符会直接结束
  • 4.需要考虑溢出的问题

在将字符串转换成数字的时候,用下面这句核心代码:

sum = sum * 10 + (str.charAt(i) - '0');

但是在这个过程中,我们依然需要考虑数字溢出的问题,这个问题其实和我们上一道题【反转整数】一样:

针对这种情况,我们可以在加和之前判断,针对大于0的情况,如果大于最大值整除10,或者等于最大值整除10,但是个位数超过了,都直接返回0。

假设最大值是127,那么sum如果大于12,肯定会超过,如果sum ==12,但是个位数大于7,乘以10相加,也肯定会超。

if (sum > Integer.MAX_VALUE/10 || (sum == Integer.MAX_VALUE / 10 && (str.charAt(i) - '0')  > 7)) return 0;

对于小于0的情况,假设最小值是-128,那么sum是数字部分 128, 如果当前sum大于 12,那么就一定超出,或者sum == 12,但是个位数大于8,乘以10,相加也会大于128,不符合要求,所以直接返回0

if (sum < Integer.MIN_VALUE/10 || (sum == Integer.MIN_VALUE / 10 && x (str.charAt(i) - '0') > 8)) return 0;

java代码实现如下:

class Solution {
    public static int myAtoi(String str) {
        if (str == null) {
            return 0;
        }
        int i = 0;
        while (i < str.length() && str.charAt(i) == ' ') {
            i++;
        }
        if (i >= str.length()
                || (str.charAt(i) != '-'
                && str.charAt(i) != '+' && !((str.charAt(i) >= '0') && (str.charAt(i) <= '9')))) {
            return 0;
        }
        int sign = 1;
        if (i < str.length() && (str.charAt(i) == '-' || i < str.length() && str.charAt(i) == '+')) {
            sign = str.charAt(i) == '-' ? -1 : 1;
            i++;
        }
        int sum = 0;
        for (; i < str.length(); i++) {
            if (str.charAt(i) >= '0' && str.charAt(i) <= '9') {
                if (sign == 1) {
                    if (sum > Integer.MAX_VALUE / 10 || sum == Integer.MAX_VALUE / 10 && (str.charAt(i) - '0') > 7) {
                        return Integer.MAX_VALUE;
                    }
                } else {
                    if (sum > (Integer.MAX_VALUE) / 10 || sum == (Integer.MAX_VALUE) / 10 && (str.charAt(i) - '0') > 8) {
                        return Integer.MIN_VALUE;
                    }
                }
                sum = sum * 10 + (str.charAt(i) - '0');
            } else {
                return sum * sign;
            }
        }
        return sum * sign;
    }
}

C++ 代码实现如下:

#include<iostream>
#include<string>
using namespace std;
class Solution {
public:
    int myAtoi(string str) {
        if (str.size() == 0) {
            return 0;
        }
        int i = 0;
        while (i < str.length() && str[i] == ' ') {
            i++;
        }
        if (i >= str.length()
            || (str[i]!= '-'
                && str[i] != '+' && !((str[i] >= '0') && (str[i] <= '9')))) {
            return 0;
        }
        int sign = 1;
        if (i < str.length() && (str[i] == '-' || i < str.length() && str[i] == '+')) {
            sign = str[i] == '-' ? -1 : 1;
            i++;
        }
      	// 需要无符号数,否则 -2147483648会溢出
        unsigned int sum = 0;
        for (; i < str.length(); i++) {
            if (str[i] >= '0' && str[i] <= '9') {
                if (sign == 1) {
                    if (sum > INT_MAX / 10 || sum == INT_MAX / 10 && (str[i]- '0') > 7) {
                        return INT_MAX;
                    }
                } else {
                    if (sum > (INT_MAX) / 10 || sum == (INT_MAX) / 10 && (str[i] - '0') > 8) {
                        return INT_MIN;
                    }
                }
                sum = sum * 10 + (str[i] - '0');
            } else {
                return sum * sign;
            }
        }
        return sum * sign;
    }
};
int main(){
    Solution solution;
    cout<< solution.myAtoi(" -2147483648")<<endl;
    return 0;
}

时间复杂度为 O(n),空间复杂度为O(1)。