LeetCode 第8题:字符串转换整数(Python3解法)

1:问题描述

来源:LeetCode

难度:中等


问题详情:
由于力扣本身题目描述的不够清楚,因此接下来使用我自己的话叙述该问题。
给定一个字符串s,读取其中的整数,但必须是以下形式:

  1. 未第一次读到数字时,字符开头的空格字符“ ”可以忽略,“+”字符代表是正整数,"-"字符代表是负整数,如果没有这二者则默认为正符号
  2. 当第一次读到数字时,以后遇到非数字字符都要停止;
  3. 如果读取的数字已经超过大于 2 31 2^{31} 231的,返回 2 31 2^{31} 231;如果小于 − 2 31 − 1 -2^{31}-1 2311的,则返回 − 2 31 − 1 -2^{31}-1 2311
  4. 如果停止时还没有读入数字,则返回为0

案例:

输入:“”
输出:0
解释:没有读到数字

输入:“+1”
输出:1

输入:“+1+1”
输出:1
解释:读取到第二个“+”时根据第2个条件,停止读取

输入:“ +1+”
输出:1
解释:根据第1条,第2条返回1

输入:“ ++1+”
输出:0
解释:根据第1条,第2条,第4条,返回为0

输入:“2147483648”
输出:”2147483647“
解释:根据第3条,超界限


2:问题分析

2.1 时间复杂度和空间复杂度

在真正开始介绍各种算法前,先以表格形式展示各自的时间复杂度和空间复杂度,其中 n n n表示字符串 s s s的长度。

算法 时间复杂度 空间复杂度
直接法 O ( n ) O(n) O(n) O ( 1 ) O(1) O(1)
正则表达式法 O ( n ) O(n) O(n) O ( 1 ) O(1) O(1)
自动机 O ( n ) O(n) O(n) O ( 1 ) O(1) O(1)

2.2 直接法

流程如下:

  1. 首先去除左边的空格
  2. 空字符串,返回为0
  3. i n d e x index index i i i 分别表示读取的数字个数、当前字符所在下标
  4. 如果第0个字符是”+“或者”-“, 则改变符号变量sign的值
  5. 如果当前第 i i i个字符不是数字,则停止;
  6. 如果当前第 i i i个字符是数字, 则判断当前整数的长度,因为 2 31 2^{31} 231的长度为10,所以小于10的不用考虑越界的问题;如果大于等于10,则需要判断。

2.2.1 代码

由于之前的问题详情里,描述的还算详细,因此直接给出代码:

def myAtoi(s: str) -> int:
    s = s.lstrip() # 去左边空格
    sign = 1
    num = 0
    MAX = 2 ** 31 - 1
    MIN = -2 ** 31
    i = 0 # 字符索引
    index = 0 # 数字索引
    # 排除空字符串
    if not s:
        return 0
       
    # 符号
    if s[0] == '+':
        i += 1
    elif s[0] == '-':
        sign = -1
        i += 1

    while i < len(s):
        if s[i].isnumeric():
            index += 1
            num = num * 10 + eval(s[i])
            
            # 数字长度超过或者等于10,则要考虑是否超过了界限
            if index >= 10:
                if num * sign >= MAX:
                    return MAX
                elif num * sign <= MIN:
                    return MIN
            i += 1
        else:
            break
    return sign * num

时间复杂度为 O ( n ) O(n) O(n),空间复杂度为 O ( 1 ) O(1) O(1)

2.3 正则表达式法

流程如下:

  1. 首先去除字符左边的空格

  2. 使用正则表达式,去匹配满足以下两种形式的一种:

    (1)正负号开头+数字
    (2)纯数字

  3. 将上述的结果转为int

  4. 然后将int类型的数值限定在32位范围内。

2.3.1 代码

def myAtoi2(s: str) -> int:
    import re
    INT_MAX = 2147483647
    INT_MIN = -2147483648
    s = s.lstrip()      #清除左边多余的空格
    num_re = re.compile(r'^[\+\-]?\d+')   #设置正则规则
    num = num_re.findall(s)   #查找匹配的内容
    num = int(*num) #由于返回的是个列表,解包并且转换成整数
    return max(min(num,INT_MAX),INT_MIN)    #返回值

r'^[\+\-]?\d+'中的:

  • ‘^’表示以后面的字符开头
  • '[\+\-]'表示正号或者负号的一种,‘\’表示转义字符
  • '?'表示匹配前面的字符串0次或者1次,也就是说前面的正负号只能出现0次或者1次
  • ‘\d+’‘\d’表示匹配0-9,而'+'表示匹配前面的字符串1次或者多次

可以得知,这样的匹配规则得到的字符串只能是一个或者没有找到,所以findall的返回结果num只能是有一个字符串的列表或者空列表。
对于int(*num)

  • num为一个字符串的列表时,比如['-123'],int(*num)就是int('-123')=123
  • num为空列表时,int(*num)=int(),int()默认为0

然后使用min()max()限定范围。

正则表达式法的时间复杂度为 O ( n ) O(n) O(n),空间复杂度为 O ( 1 ) O(1) O(1)

2.4 自动机

自动机是给定符号输入,依据(可表达为一个表格的)转移函数“跳转”过一系列状态的一种机器。

我们根据第1节中的条件,构建如下图中的状态转换。图片来源
在这里插入图片描述
共有如下状态:

  1. start
  2. end;
  3. signed;
  4. in_number;

start->signed为例,只有在开始阶段读取到正负号才进入signed状态。

同样地,使用如下表格也可以表示状态转移函数(表格来源),符号有空、正负号、数字、其它四种。
在这里插入图片描述

2.4.1 代码

接下来,就是使用代码实现这个状态转移函数:

  1. 使用table构建如上的表格;
  2. table[‘开始状态’]['列索引']得到下一个转移后的状态,初始状态为‘start’
  3. 列索引则通过当前字符得到(get_col);
  4. 转移后的状态为in_number时,判断是否越界;
  5. 转移后的状态为‘signed’时,则重新赋值正负号;
INT_MAX = 2 ** 31 - 1
INT_MIN = -2 ** 31
class Automaton:
    def __init__(self):
        self.state = 'start'
        self.sign = 1
        self.ans = 0
        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'],
        }
    
    # 根据当前输入的符号,返回表格中对应的列索引
    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):
        self.state = self.table[self.state][self.get_col(c)]  # table[开始状态][列索引]
        if self.state == 'in_number':
            self.ans = self.ans * 10 + int(c)
            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

时间复杂度为 O ( n ) O(n) O(n),空间复杂度为 O ( 1 ) O(1) O(1)

猜你喜欢

转载自blog.csdn.net/weixin_43490422/article/details/126585568
今日推荐