【LeetCode-字符串】字符串转换整数 (atoi)

题目描述

请你来实现一个 atoi 函数,使其能将字符串转换成整数。

首先,该函数会根据需要丢弃无用的开头空格字符,直到寻找到第一个非空格的字符为止。接下来的转化规则如下:

如果第一个非空字符为正或者负号时,则将该符号与之后面尽可能多的连续数字字符组合起来,形成一个有符号整数。
假如第一个非空字符是数字,则直接将其与之后连续的数字字符组合起来,形成一个整数。
该字符串在有效的整数部分之后也可能会存在多余的字符,那么这些字符可以被忽略,它们对函数不应该造成影响。
注意:假如该字符串中的第一个非空格字符不是一个有效整数字符、字符串为空或字符串仅包含空白字符时,则你的函数不需要进行转换,即无法进行有效转换。

在任何情况下,若函数不能进行有效的转换时,请返回 0 。

提示:

  • 本题中的空白字符只包括空格字符 ' ' 。
  • 假设我们的环境只能存储 32 位大小的有符号整数,那么其数值范围为 [−231,  231 − 1]。如果数值超过这个范围,请返回  INT_MAX (231 − 1) 或 INT_MIN (−231) 。

示例:

输入: "42"
输出: 42

输入: "   -42"
输出: -42
解释: 第一个非空白字符为 '-', 它是一个负号。
     我们尽可能将负号与后面所有连续出现的数字组合起来,最后得到 -42 。

输入: "4193 with words"
输出: 4193
解释: 转换截止于数字 '3' ,因为它的下一个字符不为数字。

题目描述: https://leetcode-cn.com/problems/string-to-integer-atoi/

思路

题目的要求如下:

  • 符号和数字是连在一起的,如果不连在一起则是非法的。例如,-123返回 -123,- 123返回 0;
  • 只需要将符号或者数字前面的空格消除,不用考虑后面的。例如, -123 返回 -123, -123 456 返回 -123;
  • 符号除了负号-外,正号+也可能出现;

转换步骤如下:

  • 先消除字符串前面的空格;
  • 判断正负号;
  • 提出数字字符串;
  • 数字字符串消除前导 0;
  • 判断数字字符串是否越界;
  • 将数字字符串转为数字后返回;

具体细节见代码:

class Solution {
public:
    int myAtoi(string str) {
        if(str.empty()) return 0;
        if(str.size()==1){
            if(!isdigit(str[0])) return 0;
        }

        int i = 0;
        while(str[i]==' ') i++;  // i记录前面的空格到哪个位置

        string strWithoutSpace = str.substr(i, str.size()); // 消除字符串前面的空格
        if(!(isdigit(strWithoutSpace[0]) || strWithoutSpace[0]=='-' || strWithoutSpace[0]=='+')) return 0;

        bool isNegative = false;
        if(strWithoutSpace[0]=='-') isNegative = true; 
        if(isNegative && !isdigit(strWithoutSpace[1])) return 0; // 例如"-w"直接返回0

        int j = 0; // 开始遍历的位置
        if(strWithoutSpace[0]=='-' || strWithoutSpace[0]=='+') j = 1; // 如果第0位是符号位,就从第1位开始
        string ans = "";  // 记录答案
        while(isdigit(strWithoutSpace[j])){ // 记录到第一个非数字字符为止
            ans += strWithoutSpace[j];
            j++;
        }

        int k = 0; // ans中可能有很多0,例如“000123”,k用来消除前导0
        while(ans[k]=='0') k++;
        ans = ans.substr(k, ans.size());
        if(ans.empty()) return 0; // 如果0消除后ans为空,则直接返回0

        string INT_MAX_STR = to_string(INT_MAX); // 将INT_MAX转为string
        string INT_MIN_STR = to_string(INT_MIN);
        INT_MIN_STR = INT_MIN_STR.substr(1, INT_MIN_STR.size()); // 将INT_MIN转为string并去掉负号

        // 下面的代码判断是否数字超过范围
        if(!isNegative){ // 正数
            if(ans.size()>INT_MAX_STR.size()) return INT_MAX;
            else if(ans.size()==INT_MAX_STR.size() && ans>INT_MAX_STR) return INT_MAX;
        }else{  // 负数
            if(ans.size()>INT_MAX_STR.size()) return INT_MIN;
            else if(ans.size()==INT_MAX_STR.size() && ans>INT_MAX_STR) return INT_MIN;
        }
        return isNegative? -stoi(ans):stoi(ans);
    }
};

把符号和数字部分分开考虑能简化代码。如果将符号和数字部分当成一个整体来考虑,则代码会变得复杂,如下:

class Solution {
public:
    int strToInt(string str) {
        if(str.empty()) return 0;
        if(str.size()==1 && !isdigit(str[0])) return 0;

        int i=0;
        while(str[i]==' ') i++;
        string s = str.substr(i, str.size());
        if(s.empty()) return 0;

        bool isNegative = false;
        bool firstIsSign = false;  // 首位是不是符号位
        if(s[0]=='-' || s[0]=='+') firstIsSign = true;
        if(s[0]=='-') isNegative = true;
        
        i = 0;
        if(firstIsSign){
            int j = i+1;
            //cout<<i<<" "<<j<<endl;
            while(j<s.size() && isdigit(s[j])) j++;
            if(j-i<=1) return 0;
            else s = s.substr(i, j-i);  // j-i,不是 j-i+1
        }else{
            int j = i;
            while(j<s.size() && isdigit(s[j])) j++;
            if(j==i) return 0;
            else s = s.substr(i, j-i); // j-i,不是 j-i+1
        }

        if(firstIsSign) i=1;
        else i=0;
        while(s[i]=='0') i++;
        s = s.substr(i, s.size());
        if(firstIsSign){
            if(isNegative) s = "-"+s;
            else s = "+"+s;
        }

        if(s.empty()) return 0;
        else{
            if(s.size()==1 && !isdigit(s[0])) return 0;
            if(firstIsSign && !isdigit(s[1])) return 0;
            if(!firstIsSign && !isdigit(s[0])) return 0;
        }

        string max = to_string(INT_MAX);
        string min = to_string(INT_MIN);
        if(firstIsSign && !isNegative) s = s.substr(1, s.size());  // 将 s 前的 '+' 去掉
        if(!isNegative){
            if(s.size()>max.size()) return INT_MAX;
            else if(s.size()==max.size() && s>max) return INT_MAX;
        }else{
            if(s.size()>min.size()) return INT_MIN;
            else if(s.size()==min.size() && s>min) return INT_MIN;
        }
        return stoi(s);
    }
};
  • 时间复杂度:O(n)
  • 空间复杂度:O(1)
原文地址:https://www.cnblogs.com/flix/p/13216519.html