题目描述
请你来实现一个 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)