请你来实现一个 myAtoi(string s) 函数,使其能将字符串转换成一个 32 位有符号整数(类似 C/C++ 中的 atoi 函数)。
函数 myAtoi(string s) 的算法如下:
读入字符串并丢弃无用的前导空格
检查下一个字符(假设还未到字符末尾)为正还是负号,读取该字符(如果有)。 确定最终结果是负数还是正数。 如果两者都不存在,则假定结果为正。
读入下一个字符,直到到达下一个非数字字符或到达输入的结尾。字符串的其余部分将被忽略。
将前面步骤读入的这些数字转换为整数(即,"123" -> 123, "0032" -> 32)。如果没有读入数字,则整数为 0 。必要时更改符号(从步骤 2 开始)。
如果整数数超过 32 位有符号整数范围 [−231, 231 − 1] ,需要截断这个整数,使其保持在这个范围内。具体来说,小于 −231 的整数应该被固定为 −231 ,大于 231 − 1 的整数应该被固定为 231 − 1 。
返回整数作为最终结果。
注意:
本题中的空白字符只包括空格字符 ' ' 。
除前导空格或数字后的其余字符串外,请勿忽略 任何其他字符。
示例 1:
输入:s = "42"
输出:42
解释:加粗的字符串为已经读入的字符,插入符号是当前读取的字符。
第 1 步:"42"(当前没有读入字符,因为没有前导空格)
^
第 2 步:"42"(当前没有读入字符,因为这里不存在 '-' 或者 '+')
^
第 3 步:"42"(读入 "42")
^
解析得到整数 42 。
由于 "42" 在范围 [-231, 231 - 1] 内,最终结果为 42 。
示例 2:
输入:s = " -42"
输出:-42
解释:
第 1 步:" -42"(读入前导空格,但忽视掉)
^
第 2 步:" -42"(读入 '-' 字符,所以结果应该是负数)
^
第 3 步:" -42"(读入 "42")
^
解析得到整数 -42 。
由于 "-42" 在范围 [-231, 231 - 1] 内,最终结果为 -42 。
示例 3:
输入:s = "4193 with words"
输出:4193
解释:
第 1 步:"4193 with words"(当前没有读入字符,因为没有前导空格)
^
第 2 步:"4193 with words"(当前没有读入字符,因为这里不存在 '-' 或者 '+')
^
第 3 步:"4193 with words"(读入 "4193";由于下一个字符不是一个数字,所以读入停止)
^
解析得到整数 4193 。
由于 "4193" 在范围 [-231, 231 - 1] 内,最终结果为 4193 。
提示:
0 <= s.length <= 200
s 由英文字母(大写和小写)、数字(0-9)、' '、'+'、'-' 和 '.' 组成
我的题解:完全是面向测试用例穷举编程(笑哭)
class Solution:
def myAtoi(self, s: str) -> int:
sign = 1
num = 0
count = 0
pre = ""
for v in s:
if(v == ' '):
if(pre == "+" or pre == "-"):
return 0
elif(pre >= '0' and pre <= '9'):
return sign * num
continue
elif(v == "-"):
if(pre >= '0' and pre <= '9'):
return sign * num
sign = -1
count += 1
elif(v == "+"):
if(pre >= '0' and pre <= '9'):
return sign * num
sign = 1
count += 1
elif(v >= '0' and v <= '9'):
num *= 10
num += int(v)
else:
break
pre = v
num *= sign
if(num < -2 ** 31):
num = -2 ** 31
elif(num > 2 ** 31 -1):
num = 2 ** 31 -1
if(count > 1):
return 0
return num
官解:
根据问题的描述我们来判断并且描述对应的解题方法。对于这道题目,很明显是字符串的转化问题。需要明确转化规则,尽量根据转化规则编写对应的子函数。
这里我们要进行模式识别,一旦涉及整数的运算,我们需要注意溢出。本题可能产生溢出的步骤在于推入、乘以 10 操作和累加操作都可能造成溢出。对于溢出的处理方式通常可以转换为 INT_MAX 的逆操作。比如判断某数乘以 10 是否会溢出,那么就把该数和 INT_MAX 除以 10 进行比较。
模式识别:所谓模式识别的问题就是用计算的方法根据样本的特征将样本划分到一定的类别中去。模式识别就是通过计算机用数学技术方法来研究模式的自动处理和判读,把环境与客体统称为“模式”。随着计算机技术的发展,人类有可能研究复杂的信息处理过程,其过程的一个重要形式是生命体对环境及客体的识别。模式识别以图像处理与计算机视觉、语音语言信息处理、脑网络组、类脑智能等为主要研究方向,研究人类模式识别的机理以及有效的计算方法。
方法一:自动机
思路字符串处理的题目往往涉及复杂的流程以及条件情况,如果直接上手写程序,一不小心就会写出极其臃肿的代码。
因此,为了有条理地分析每个输入字符的处理方法,我们可以使用自动机这个概念:
我们的程序在每个时刻有一个状态 s,每次从序列中输入一个字符 c,并根据字符 c 转移到下一个状态 s'。这样,我们只需要建立一个覆盖所有情况的从 s 与 c 映射到 s' 的表格即可解决题目中的问题。
算法
本题可以建立如下图所示的自动机:
#整数的最大值与最小值界限
INT_MAX = 2 ** 31 - 1
INT_MIN = -2 ** 31
#处理输入字符的自动机类
class Automaton:
'''
函数中的第一个参数,都是self,Class中的函数里面,访问对应的变量(读取或者写入),以及调用对应的函数时,经常有以下代码:self.XXX()
Python中为何要有self:在类的代码(函数)中,需要访问当前的实例中的变量和函数的,即,访问Instance中的:
对应的变量(property):Instance.ProperyNam,去读取之前的值和写入新的值
调用对应函数(function):Instance.function(),即执行对应的动作
而需要访问实例的变量和调用实例的函数,当然需要对应的实例Instance对象本身
而Python中就规定好了,函数的第一个参数,就必须是实例对象本身,并且建议,约定俗成,把其名字写为self,以safe为前缀的变量都可供类中的所有方法使用
所以,我们需要self(需要用到self)
def __init__(self)是用于初始化类,当使用类名()的方法去创建对象的时候,python解释器会自动调用__init__方法,因此可以在__init__方法中做一些初始化的设定,在每次创建新对象时,都自动完成这些初始化的设定
'''
def __init__(self):#__是两个下划线
self.state = 'start'#初始状态
self.sign = 1#默认的符号
self.ans = 0#整数的值
#这是一个字典,字典中的键‘start’对应一个列表,列表是有索引的
# ' ' +/- number other
self.table = {
'start' : ['start', 'signed', 'in_number', 'end'],
'signed' : ['end', 'end', 'in_number', 'end'],
'in_number' : ['end', 'end', 'in_number', 'end'],
'end' : ['end', 'end', 'end', 'end'],
}
#根据接下来读取的c这个字符是什么字符来返回接下来的状态对应的索引
def get_col(self, c):
if c.isspace():#判断是否是空格
return 0
if c == '+' or c == '-':#判断是否是+、-
return 1
if c.isdigit():#判断是否是数字
return 2
#判断是否是其他字符
return 3
#根据状态对应的索引返回状态,并进行相应的操作
def get(self, c):
#调用get_col()函数
self.state = self.table[self.state][self.get_col(c)]
#如果是start状态则什么也不用改变继续进行,是end状态则接下来的所有操作无效
if self.state == 'in_number':
self.ans = self.ans * 10 + int(c)
#在运算过程中self.ans是正数
#value_when_true if condition_is_ture else value_when_condition_is_false
self.ans = min(self.ans, INT_MAX) if self.sign == 1 else min(self.ans, -INT_MIN)
elif self.state == 'signed':
self.sign = 1 if c == '+' else -1
class Solution:
def myAtoi(self, str: str) -> int:
#创建对象
automaton = Automaton()
#遍历字符串
for c in str:
automaton.get(c)
return automaton.sign * automaton.ans
大神的解法:
class Solution:
def myAtoi(self, s: str) -> int:
INT_MIN, INT_MAX = -2**31, 2**31-1
s = s.strip()#用于移除字符串头尾指定的字符
#如果s字符串里只有空格,则返回0
if not s: return 0
i, sign = 0, 1#初始索引和符号
res = 0#初始整数值
if s[0] in '+-':
sign = 1 if s[0] == '+' else -1
i += 1
while i < len(s):
if not s[i].isdigit(): break#isdigit()返回的是布尔值:True False
res = res * 10 + int(s[i])
if not INT_MIN <= sign * res <= INT_MAX:
return INT_MIN if sign * res < INT_MIN else INT_MAX
i += 1
return sign * res