• 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
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34

    时间复杂度为 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)    #返回值
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    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
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39

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

  • 相关阅读:
    ArcGIS API for JavaScript 4.x 实现动态脉冲效果
    了解.NET Framework中自带的泛型委托Predicate和Comparison
    自用文章汇总
    802. 找到最终的安全状态
    阿里云2核4G服务器5M带宽5年费用价格明细表
    Elasticsearch
    [C++]杨辉三角
    【押题】24考研押题
    python变量
    实验二 逻辑回归算法实验
  • 原文地址:https://blog.csdn.net/weixin_43490422/article/details/126585568