zoukankan      html  css  js  c++  java
  • 【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)
  • 相关阅读:
    剑指offer(45)扑克牌顺子
    剑指offer(44)单词翻转序列
    剑指offer(43)左旋转字符串
    剑指offer(42)和为S的字符串
    剑指offer(41)和为S的连续正数序列
    剑指offer(40)数组中只出现一次的数字
    剑指offer(39)平衡二叉树
    面试金典——字符串压缩
    LeetCode——恢复二叉搜索树
    LeetCode——修剪二叉搜索树
  • 原文地址:https://www.cnblogs.com/flix/p/13216519.html
Copyright © 2011-2022 走看看