字符串转换整数-atoi
题目
请你来实现一个 myAtoi(string s)
函数, 使其 能将字符串转换成一个 32
位有符号整数(类似 C/C++ 中的 atoi
函数).
函数 myAtoi(string s)
的算法如下:
- 读入字符串并丢弃无用的前导空格
- 检查下一个字符(假设还未到字符末尾)为正还是负号, 读取该字符(如果有). 确定最终结果是负数还是正数. 如果两者都不存在, 则假定结果为正.
- 读入下一个字符, 直到到达下一个非数字字符或到达输入的结尾. 字符串的其余部分将被忽略.
- 将前面步骤读入的这些数字转换为整数(即,
"123" -> 123
,"0032" -> 32
). 如果没有读入数字, 则整数为0
. 必要时更改符号(从步骤 2 开始). - 如果整数数超过
32
位有符号整数范围[-2³¹, 2³¹ - 1]
, 需要截断这个整数, 使其保持在这个范围内. 具体来说, 小于-2³¹
的整数应该被固定为-2³¹
, 大于2³¹ - 1
的整数应该被固定为2³¹ - 1
. - 返回整数作为最终结果.
注意:
- 本题中的空白字符只包括空格字符 ' '.
- 除前导空格或数字后的其余字符串外, 请勿忽略任何其他字符.
提示:
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.
题解
- JavaScript
- Rust
/**
* @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
}
pub fn my_atoi(s: String) -> i32 {
let n = s.len();
let s = s.as_bytes();
let mut sign = 1;
let mut ans = 0;
let mut i = 0;
// rust 注意时时刻刻要判断 i < n, 否则 s[i] 取到空指针会报错
while i < n && s[i] == b' ' {
i += 1;
}
// rust 注意时时刻刻要判断 i < n, 否则 s[i] 取到空指针会报错
if i < n && s[i] == b'-' {
sign = -1;
}
// rust 注意时时刻刻要判断 i < n, 否则 s[i] 取到空指针会报错
if i < n && (s[i] == b'+' || s[i] == b'-') {
i += 1;
}
// rust 注意时时刻刻要判断 i < n, 否则 s[i] 取到空指针会报错
while i < n && is_digit(s[i]) {
// u8 转 i32 的小技巧
let num = (s[i] - b'0') as i32;
if ans > i32::MAX / 10 || (ans == i32::MAX / 10 && num > i32::MAX % 10) {
if sign < 0 {
return i32::MIN;
} else {
return i32::MAX;
}
}
ans = ans * 10 + num;
i += 1;
}
if sign < 0 {
return -ans;
} else {
return ans;
}
}
fn is_digit(num: u8) -> bool {
num >= b'0' && num <= b'9'
}