Skip to main content

字符串转换整数-atoi

题目

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

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

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

注意:

  • 本题中的空白字符只包括空格字符 ' '.
  • 除前导空格或数字后的其余字符串外, 请勿忽略任何其他字符.
提示:
  • 0 <= s.length <= 200
  • s 由英文字母(大写和小写), 数字(0-9), ' ', '+', '-''.' 组成
示例
输入: s = "42"
输出: 42
解释: 加粗的字符串为已经读入的字符, 插入符号是当前读取的字符.
1: "42"(当前没有读入字符, 因为没有前导空格)
^
2: "42"(当前没有读入字符, 因为这里不存在 '-' 或者 '+')
^
3: "42"(读入 "42")
^
解析得到整数 42.
由于 "42" 在范围 [-2³¹, 2³¹ - 1], 最终结果为 42.
输入: s = "   -42"
输出: -42
解释:
1: " -42"(读入前导空格, 但忽视掉)
^
2: " -42"(读入 '-' 字符, 所以结果应该是负数)
^
3: " -42"(读入 "42")
^
解析得到整数 -42.
由于 "-42" 在范围 [-2³¹, 2³¹ - 1], 最终结果为 -42.
输入: s = "4193 with words"
输出: 4193
解释:
1: "4193 with words"(当前没有读入字符, 因为没有前导空格)
^
2: "4193 with words"(当前没有读入字符, 因为这里不存在 '-' 或者 '+')
^
3: "4193 with words"(读入 "4193"; 由于下一个字符不是一个数字, 所以读入停止)
^
解析得到整数 4193.
由于 "4193" 在范围 [-2³¹, 2³¹ - 1], 最终结果为 4193.

题解

/**
* @param {string} s
* @return {number}
*/
var myAtoi = function (s) {
const INT_MAX = 2 ** 31 - 1
const INT_MIN = (-2) ** 31
const n = s.length
let ans = 0
let sign = 1
let i = 0

// 如果开头是空格, 跳过
while (s[i] === ' ') i++

// 跳过开头的空格们后, 如果遇见负号, 记录一下
// 至于为什么命名为 sign, 且如果是正数, sign 为 1; 如果是负数, sign 为 -1
// 是遵循的规范: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/sign
if (s[i] === '-') sign = -1

// 跳过开头的空格们后, 如果遇见正号或者负号, 跳过
if (s[i] === '+' || s[i] === '-') i++

// 跳过开头的空格和正负号后, 找后面的元素是否为数字
while (i < n && /[0-9]/.test(s[i])) {
const num = Number(s[i])

// 注意这块比较有意思, 思路是通过 INT_MAX 逆过来(INT_MAX / 10), 来推断 ans 是否溢出
// 首先注意 INT_MAX 是 2147483647
// 如果当前的 ans 大于 INT_MAX / 10, 说明溢出了, 需要返回 INT_MAX 或者 INT_MIN
// 如果当前的 ans 等于 INT_MAX / 10 后取整, 也就是 214748364, 但 num 仍大于 INT_MAX 取余, (其实就是 INT_MAX 的最后一位, 也就是 7), 也说明溢出了
if (
ans > INT_MAX / 10 ||
(ans === ((INT_MAX / 10) | 0) && num > INT_MAX % 10)
) {
// 根据正负返回 INT_MAX 还是 INT_MIN
return sign > 0 ? INT_MAX : INT_MIN
}

// 如果是数字, 加入到 ans 中
ans = ans * 10 + num

// 指针往后走
i++
}

// 根据正负返回 ans 还是 -ans
return sign > 0 ? ans : -ans
}