题目:实现一个将字符串转换为整数的函数atoi。
- 该函数首先丢弃空白字符,直到找到第一个非空白字符。然后,从该字符开始,采用可选的初始加号或减号,后跟尽可能多的数字,并将它们解释为数值。
- 字符串可以包含在形成整数之后的其他字符,这些字符将被忽略并且对此函数的行为没有影响。
- 如果str中的第一个非空白字符序列不是有效的整数,或者由于str是空的或者只包含空格字符而不存在这样的序列,则不执行转换。如果无法执行有效转换,则返回零值。
- 只有空格字符
' '
被视为空白字符。 - 假设我们正在处理一个只能在32位有符号整数范围内存储整数的环境:[ - 2^31,2^31 - 1]。如果数值超出表示的值的范围的,INT_MAX(2^31 - 1)或INT_MIN(- 2^31)被返回。
例: Input: "42" Output: 42;
Input: " -42" Output: -42;
Input: "4193 with words" Output: 4193;
Input: "words and 987" Output: 0;(输入字符串第一个非空白字符‘w’不是有效的整数,返回0)
Input: "-91283472332" Output: -2147483648。(输入字符串转化为整数超过范围,输出- 2^31)
方法一:此题主要是需要考虑好多种特例情况,只要有一种没考虑到,就会报错。笔者在调试的过程中出现了好多问题,而且对题目没有了解透彻。开始时笔者使用replace(' ','')替换掉了字符串中的所有空格,就出现了下面的报错。因为中间的空格和其他非数字字符会起到截断整数的作用,即其后面的任意字符不再作为整数的组成部分。于是换成了strip(' '),只去掉第一个非白字符之前的空白字符。其后需要考虑去除前面空白字符后的字符串长度,长度为0,返回0;长度为1,如果是数字,返回整数,非数字返回0;如果长度>1,需要考虑四种情况:第一非空白字符分别是+,-,数字,其他字符。如果是+或-,后面紧跟数字,就相应返回整数,如果后面紧跟截断字符(非数字字符),就返回0;如果是第一非空白字符是其他字符,也返回0。此外,要考虑溢出情况的输出。代码如下。
class Solution:
def len1(self,str):
#除去前面空白字符,字符串长度为1的情况
if str[0].isdigit():
return int(str)
else:
return 0
def myAtoi(self, str: str) -> int:
str=str.strip(' ')
lenS=len(str)
if lenS==0:
return 0
if lenS==1:
r=self.len1(str)
return r
if (str[0].isdigit())|(str[0] in ['+','-']):
later=str[1:]
#找截断字符,只去截断字符前面的部分组成整数
for c in later:
if not c.isdigit():
later=later.split(c)[0]
break
if len(later)==0:
r=self.len1(str[0])
return r
elif str[0]=='-':
r=int(later)*(-1)
elif str[0]=='+':
r=int(later)
else:
r=int(str[0]+later)
#考虑整数溢出
int_min=math.pow(2,31)*(-1)
int_max=math.pow(2,31)-1
if r<int_min:
return int(int_min)
elif r>int_max:
return int(int_max)
else:
return r
else:
#第一个非空白字符不是数字,也不是‘+’,‘-’
return 0
方法二:翻看讨论区还有使用正则表达式的方法,非常简洁,而且速度快,值得学习。pattern表示匹配的正则表达式,意思是匹配到一个开头有任意个空白字符(包括0个)后面是‘+’或‘-’或‘’,再后面是>=1个数字的字符串。如果匹配到,只需将后面匹配的数字部分转为整数,如果为有‘-’,乘上-1即可。具体模式解释如下:
模式 | 描述 |
^ | 匹配字符串的开头 |
\s | 匹配任意空白字符,等价于 [\t\n\r\f]. |
* | 匹配前面的字符或者子表达式0次或多次 |
( ) | 匹配括号内的表达式,也表示一个组 |
?P<name> | 命名一个名字为name的组,匹配规则满足后面的表达式 |
[...] | 用来表示一组字符,单独列出:[amk] 匹配 'a','m'或'k' |
? | 表示前面的内容可有可无 |
[0-9] | 匹配 [0123456789]中的任何一个数字 |
+ | 匹配前面的字符或者子表达式1次或多次 |
代码如下:
class Solution(object):
def myAtoi(self, str: str) -> int:
import re
pattern = r'^\s*(?P<sign>[-\+]?)(?P<number>[0-9]+)'
m = re.search(pattern, str)
if m:
result = int(m.group('number'))
if m.group('sign') == '-':
result = -1 * result
if result < -2 ** 31:
return -2 ** 31
if result > 2 ** 31 - 1:
return 2 ** 31 - 1
return result
else:
return 0