文章目录
-
- 题目
- 解法一(排除法Python)
- 解法二(正向逻辑C#)
- 解法三(有限状态机 C语言)
题目
请你来实现一个 atoi 函数,使其能将字符串转换成整数。
首先,该函数会根据需要丢弃无用的开头空格字符,直到寻找到第一个非空格的字符为止。接下来的转化规则如下:
如果第一个非空字符为正或者负号时,则将该符号与之后面尽可能多的连续数字字符组合起来,形成一个有符号整数。
假如第一个非空字符是数字,则直接将其与之后连续的数字字符组合起来,形成一个整数。
该字符串在有效的整数部分之后也可能会存在多余的字符,那么这些字符可以被忽略,它们对函数不应该造成影响。
注意:假如该字符串中的第一个非空格字符不是一个有效整数字符、字符串为空或字符串仅包含空白字符时,则你的函数不需要进行转换,即无法进行有效转换。
在任何情况下,若函数不能进行有效的转换时,请返回 0 。
提示:
本题中的空白字符只包括空格字符 ’ ’ 。
假设我们的环境只能存储 32 位大小的有符号整数,那么其数值范围为 [−231, 231 − 1]。如果数值超过这个范围,请返回 INT_MAX (231 − 1) 或 INT_MIN (−231) 。
示例 1:
输入: “42”
输出: 42
示例 2:
输入: " -42"
输出: -42
解释: 第一个非空白字符为 ‘-’, 它是一个负号。
我们尽可能将负号与后面所有连续出现的数字组合起来,最后得到 -42 。
示例 3:
输入: “4193 with words”
输出: 4193
解释: 转换截止于数字 ‘3’ ,因为它的下一个字符不为数字。
示例 4:
输入: “words and 987”
输出: 0
解释: 第一个非空字符是 ‘w’, 但它不是数字或正、负号。
因此无法执行有效的转换。
示例 5:
输入: “-91283472332”
输出: -2147483648
解释: 数字 “-91283472332” 超过 32 位有符号整数范围。
因此返回 INT_MIN (−231) 。
解法一(排除法Python)
思路:首先对字符串进行处理,先排除各种意外情况,则剩下的部分即为有效数字。
- 处理字符开头的空格、’0‘、正负号
- 读取有效数值组成的字符集合
- 使用字符串比较来判断是否越界,返回有效字符
- 时间复杂度:O(n)
- 空间复杂度:O(n)
#author: suoxd123@126.com
class Solution:
def myAtoi(self, str1: str) -> int:
str1 = str1.lstrip()
if len(str1) == 0:
return 0
idx,flag = 0, True
if str1[0] == '-': #提取符号
flag = False
str1 = str1[1:]
elif str1[0] == '+':
str1 = str1[1:]
while len(str1) > 0 and str1[0] == '0': #去掉0开头
str1 = str1[1:]
while idx < len(str1):#提取有效数字
if not('0' <= str1[idx] <= '9'):
break
idx += 1
numStr = str1[0:idx]
numMaxStr, numMinStr = str(2**31 - 1), str(2**31)
if idx == 0: #长度为0
return 0
elif (idx > 10 or idx == 10 and numStr > numMaxStr) and flag: #大于最大值
return int(numMaxStr)
elif (idx > 10 or idx == 10 and numStr > numMinStr) and not flag: #小于最小值
return -int(numMinStr)
else:#一般情况
return int(numStr) * (1 if flag else -1)
解法二(正向逻辑C#)
思路:直接对每个字符进行判断和审查,将读取到的数值使用Long型变量存储和查看是否对Int溢出。
- 使用flag标记是否进入数值模式,一旦进入数值模式,任何其它字符出现都将退出
- 使用num保存当前已经记录的数值
- 任何出现的其它字符都属于结束后续检查
- 时间复杂度:O(n)
- 空间复杂度:O(1)
//author: suoxd123@126.com
public class Solution {
public int MyAtoi(string str) {
bool nagetive = false , flag = false;
long num = 0;
long minN = 0-(long)Math.Pow(2,31),maxN = (long)Math.Pow(2,31) - 1;
for(int i=0;i<str.Length;i++)
{
if(str[i] == '-' || str[i] == '+')
{//符号
if(flag == true)
break;
flag = true;
if(str[i] == '-')
{
nagetive = true;
}
}
else if(str[i] <= '9' && str[i] >= '0')
{//数值
flag = true; //标记是否已经进入计数模式
num = num * 10 + (str[i] - '0') * (nagetive?-1:1);
if(num>maxN || num < minN)
{
if(num < minN)
num = minN;
else
num = maxN;
break;
}
}
else if(str[i] == ' ')
{//空格
if(flag == true)
break;
continue;
}
else
{//其它字符
break;
}
}
return (int)(num);
}
}
解法三(有限状态机 C语言)
思路:使用状态机的思路来,搞清楚不同状态之间的切换关系即可,本题根据空格、符号、数值和其它字符4种类型,可以定义开始、符号、数值和结束4个状态,状态跳转如下表(横坐标为当前状态,纵坐标为当前字符,跳转表指当前状态遇到当前字符的下一个状态):
当前状态 | 空格 | 正负号 | 数值 | 其它字符 |
---|---|---|---|---|
开始 | 开始 | 符号 | 数值 | 结束 |
符号 | 结束 | 结束 | 数值 | 结束 |
数值 | 结束 | 结束 | 数值 | 结束 |
结束 | 结束 | 结束 | 结束 | 结束 |
- 定义状态跳转矩阵和跳转函数
- 循环读取当前字符,直到状态进入结束
- 当前结果转换为字符串
- 时间复杂度:O(n)
- 空间复杂度:O(1)
//author: suoxd123@126.com
int getStatus(int lastStatus,char currentChar){//状态跳转
int currentStatus = 0;
const int status[4][4] = {//状态跳转矩阵
{1,2,3,4},
{4,4,3,4},
{4,4,3,4},
{4,4,4,4}
};
if(currentChar == ' '){
currentStatus = 1;
}
else if(currentChar == '+' || currentChar == '-'){
currentStatus = 2;
}
else if(currentChar >= '0' && currentChar <= '9'){
currentStatus = 3;
}
else{
currentStatus = 4;
}
return status[lastStatus-1][currentStatus-1];
}
int myAtoi(char * str){
int status = 1, sign = 1; //状态默认是1(开始状态)
char numChar = *str++;
long val = 0;
int intMax = 0x7FFFFFFF, intMin = -0x80000000;
while(status < 4 && numChar != '\0'){
status = getStatus(status,numChar);
if(status == 2){//符号
sign = (numChar == '-' ? -1:1);
}
else if(status == 3){//数值
val = val * 10 + sign * (numChar - '0');
if(sign == 1){//检查向上越界
val = val > intMax?intMax:val;
}
else{//检查向下越界
val = val < intMin?intMin:val;
}
}
numChar = *str++;
}
return (int)val;
}