【Leetcode】字符串 string 补充知识

  • 有限状态机

请你来实现一个 myAtoi(string s) 函数,使其能将字符串转换成一个 32 位有符号整数(类似 C/C++ 中的 atoi 函数)。

函数 myAtoi(string s) 的算法如下:

  1. 读入字符串并丢弃无用的前导空格
  2. 检查下一个字符(假设还未到字符末尾)为正还是负号,读取该字符(如果有)。 确定最终结果是负数还是正数。 如果两者都不存在,则假定结果为正。
  3. 读入下一个字符,直到到达下一个非数字字符或到达输入的结尾。字符串的其余部分将被忽略。
  4. 将前面步骤读入的这些数字转换为整数(即,"123" -> 123, "0032" -> 32)。如果没有读入数字,则整数为 0 。必要时更改符号(从步骤 2 开始)。
  5. 如果整数数超过 32 位有符号整数范围 [−2^31,  2^31−1] ,需要截断这个整数,使其保持在这个范围内。具体来说,小于 −2^31 的整数应该被固定为 −2^31 ,大于 2^31−1 的整数应该被固定为 2^31−1 。
  6. 返回整数作为最终结果。

步骤:1.写出状态转移表格,定义初始状态

           2.获取当前状态

           3.根据当前状态查表更新下一状态

''+/-0-9other
startstartsignnumberend
signendendnumberend
numberendendnumberend
endendendendend
#力扣官方题解
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)]  #更新状态
        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

优化点:如果写在同个类里可以当状态更新为“end”时结束循环

  • 正则表达式

请你来实现一个 myAtoi(string s) 函数,使其能将字符串转换成一个 32 位有符号整数(类似 C/C++ 中的 atoi 函数)。

函数 myAtoi(string s) 的算法如下:

  1. 读入字符串并丢弃无用的前导空格
  2. 检查下一个字符(假设还未到字符末尾)为正还是负号,读取该字符(如果有)。 确定最终结果是负数还是正数。 如果两者都不存在,则假定结果为正。
  3. 读入下一个字符,直到到达下一个非数字字符或到达输入的结尾。字符串的其余部分将被忽略。
  4. 将前面步骤读入的这些数字转换为整数(即,"123" -> 123, "0032" -> 32)。如果没有读入数字,则整数为 0 。必要时更改符号(从步骤 2 开始)。
  5. 如果整数数超过 32 位有符号整数范围 [−2^31,  2^31−1] ,需要截断这个整数,使其保持在这个范围内。具体来说,小于 −2^31 的整数应该被固定为 −2^31 ,大于 2^31−1 的整数应该被固定为 2^31−1 。
  6. 返回整数作为最终结果。

正则规则总结

        1.^:指定开头                                                   ^s 匹配以s开头的字符串

        2.$:指定结尾                                                   aaa$匹配以aaa结尾的字符串

           ^ $同时使用:精准匹配                                  ^saaa$只能匹配saaa

        3.转义序列需要添加\:                                      \.匹配带.的字符串

        4.字符簇[]:                                                       [a-zA-Z]匹配英文字符串

           ^[]同时使用:^表示“排除的意思”                     [^A-Z]匹配非大写字符串

        5..可以匹配任何字符(\n \r除外)                          ^.a$匹配任意长度为2且以a结尾的字符串

        6.{}限制出现次数:{m,n} 代表出现[m,n]次         a{3,}$匹配任意以3个及3个以上a结尾的字符串

           简化表达:?={0,1}      *={0,}       +={1.}

        7.\d,\w,\s - 匹配数字、字符、空格。

           \D,\W,\S - 匹配非数字、非字符、非空格

题目需要的匹配规则:^[\+\-0-9]?\d*    ^[\+\-]?\d+ 

import re
class Solution:
    def myAtoi(self, str: str) -> int:
        INT_MIN = -2147483648
        INT_MAX = 2147483647    
        str = str.lstrip()                     #清除左边多余的空格
        num_rule = re.compile(r'^[\+\-]?\d+')  #设置正则规则
        num = num_rule.findall(str)             #查找匹配的内容
        #num = ['-123']
        num = int(*num)                        #解包并且转换成整数
        return max(min(num,INT_MAX),INT_MIN)              
  • Manacher 

Manacher算法:线性复杂度  O(2*len+3)——竞赛难度...别为难我了(哭

(44 封私信 / 80 条消息) 有什么浅显易懂的Manacher Algorithm讲解? - 知乎 (zhihu.com)

def manacher(s):
    T = '#'.join('^{}$'.format(s))   
    #原奇数长度的字符串插入偶数个字符长度仍为奇,原偶数长度的字符串插入奇数个字符长度变为奇,这样能保证子串长度只为奇;
    #由于边界符号不同,到边界时自动结束循环,减少了对越界条件的判断;      
    P = [0] * len(T)
    R, C = 0,                       #使用中心下标C和尾部下标R
    for i in range(1,len(T) - 1):   #以每个字符作为对称中心
        if i < R:
            P[i] = min(P[2 * C - i], R - i)
        
        while T[i+(P[i]+1)] == T[i-(P[i]+1)]:
            P[i] += 1
        
        if i + P[i] > R:
            R, C = i + P[i], i
    return P
  • 动态规划

给你一个字符串 s ,请你统计并返回这个字符串中 回文子串 的数目。

动态规划三步骤:穷举分析—确定边界—确定最优子结构(找规律)

状态定义:dp[i, j]表示以第i位开头以第j位结尾的字符串是否是回文串

边界:i—[0, len(s)-1]  j—[i,len(s)]

根据回文串性质可知:由 dp[i, j]== True 加上 s[i-1]==s[j+1] 可以推导出 dp[i-1,j+1]==True

最优子结构:dp[i, j] = s[i]==s[j] + dp[i+1,j-1]==True      所以对i遍历时需要倒序,对j遍历则需要正序;

                     但推导公式是向两边同时扩展得到,不适用于字符串初始长度为1/2的情况;

                     完整规律:i=j时,回文串成立;i=j-1时,回文串成立;其余情况,递推;

class Solution:
    def countSubstrings(self, s: str) -> int:
        dp = [[False] * len(s) for _ in range(len(s))]
        result = 0
        for i in range(len(s)-1, -1, -1): #i倒序遍历
            for j in range(i, len(s)):    #j正序遍历
                if s[i] == s[j]:
                    if j - i <= 1:        #情况一和情况二
                        result += 1
                        dp[i][j] = True
                    elif dp[i+1][j-1]:    #情况三
                        result += 1
                        dp[i][j] = True
        return result
  • 24
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值