2021年02月12日 周五 天气晴 【不悲叹过去,不荒废现在,不惧怕未来】
1. 问题简介
2. 情况复杂,考虑仔细
2.1 一刷(2021.2.12)
class Solution {
public:
int strToInt(string str) {
int res = 0, bndry = INT_MAX / 10;
int i = 0, sign = 1, length = str.size();
if(length == 0) return 0;
// 删除开头的空格
while(str.at(i) == ' ')
if(++i == length) return 0;
// 判断是否是负数
if(str.at(i) == '-') sign = -1;
// 跳过符号位
if(str.at(i) == '-' || str.at(i) == '+') ++i;
// 计算数值的大小
for(int j = i; j < length; j++) {
// 不是数字直接退出
if(str.at(j) < '0' || str.at(j) > '9') break;
// 巧妙判断数字是否越界
if(res > bndry || res == bndry && str.at(j) > '7')
return sign == 1 ? INT_MAX : INT_MIN;
res = res * 10 + (str.at(j) - '0');
}
return sign * res;
}
};
2.2 二刷(2021.3.15)
一刷的时候是直接复现的大佬的代码,二刷的时候自己写了一遍,发现了不一样的感觉,主要是判断数字是否越界那里,大佬的写法很巧妙,但是不容易想到,我的这种方法简单直接,真正面试时比较容易想出来。
class Solution {
public:
int myAtoi(string s) {
const int n = s.size();
int i = 0, num = 0;
bool sign = true;
// 删除开头的空格
while(i<n && s[i]==' ') ++i;
if(i>=n) return 0;
// 判断是否是负数
if(s[i]=='-') sign = false;
// 跳过符号位
if(s[i]=='-' || s[i]=='+') ++i;
// 计算数值的大小
int tmp = 0;
while(i<n && isdigit(s[i])){
tmp = s[i]-'0';
// 判断数字是否越界
if(num<=(INT_MAX-tmp)/10) num = 10*num + tmp;
else break;
++i;
}
// 这里需要注意的是 if 的条件,不能用 if(num<=(INT_MAX-tmp)/10) 来判断
// 原因是 num 的值本身可能略小于 INT_MAX,就会出现 num>(INT_MAX-tmp)/10,就没法返回 num 了
if(i<n && isdigit(s[i])) return sign?INT_MAX:INT_MIN;
else return sign?num:-num;
}
};
2.3 考虑无效输入和整型溢出
《剑指offer 第二版》这本书上考虑了无效的输入(如果没有读到数字,则认为输入是无效的)和整型溢出的情况,这时候就会稍微麻烦点儿,需要用两个全局标志变量来体现,代码也稍有改动。
是否为无效的输入在判断完符号位之后就可以进行确认了,而整型溢出又分为 INT_MIN 溢出和 INT_MAX 溢出两种情况,因为在判断是否溢出时,使用的是 INT_MAX(2147483647),所以当输入为 INT_MIN(-2147483648) 也被认为是溢出了,这种情况需要特殊考虑。
class Solution {
public:
bool isVaild = true;
bool isOverflow = false;
public:
int myAtoi(string s) {
// 默认输入是有效的,且没有溢出
isVaild = true;
isOverflow = false;
const int n = s.size();
int i = 0, num = 0;
bool sign = true;
// 删除开头的空格
while (i < n && s[i] == ' ') ++i;
// 判断是否是负数
if (i < n && s[i] == '-') sign = false;
// 跳过符号位
if (i < n && (s[i] == '-' || s[i] == '+')) ++i;
// 判断输入是否有效(如果没有读到数字,则认为输入是无效的)
if (i >= n || !isdigit(s[i])) {
isVaild = false;
return 0;
}
// 计算数值的大小
int tmp = 0;
while (i < n && isdigit(s[i])) {
tmp = s[i] - '0';
// 判断数字是否越界(因为使用的是 INT_MAX(2147483647) 来判断是否越界,所以 -2147483648 会被认为越界了)
if (num <= (INT_MAX - tmp) / 10) num = 10 * num + tmp;
else break;
++i;
}
// 这里需要注意 if 的条件,不能用 if(num<=(INT_MAX-tmp)/10) 来判断
// 原因是 num 的值本身可能略小于 INT_MAX,就会出现 num>(INT_MAX-tmp)/10,就没法返回 num 了
if (i < n && isdigit(s[i])) {
// 如果输入不是最小的整数 INT_MIN(-2147483648),说明真的越界了
if (!(sign == false && num == INT_MAX / 10 && tmp == 8)) isOverflow = true;
return sign ? INT_MAX : INT_MIN;
}
else return sign ? num : -num;
}
};
参考文献
《剑指offer 第二版》
https://leetcode-cn.com/problems/ba-zi-fu-chuan-zhuan-huan-cheng-zheng-shu-lcof/solution/mian-shi-ti-67-ba-zi-fu-chuan-zhuan-huan-cheng-z-4/