剑指 Offer 67. 把字符串转换成整数(情况复杂,考虑仔细)

2021年02月12日 周五 天气晴 【不悲叹过去,不荒废现在,不惧怕未来】


1. 问题简介

剑指 Offer 67. 把字符串转换成整数

在这里插入图片描述
在这里插入图片描述

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/

猜你喜欢

转载自blog.csdn.net/m0_37433111/article/details/113797685
今日推荐