LeetCode6-10


LeetCode: https://leetcode-cn.com/problemset/all/.

6.Z字形变换

难度:中等
将一个给定字符串 s 根据给定的行数 numRows ,以从上往下、从左到右进行 Z 字形排列。

示例1:
输入:s = “PAYPALISHIRING”, numRows = 3
输出:“PAHNAPLSIIGYIR”
在这里插入图片描述
示例2:
输入:s = “PAYPALISHIRING”, numRows = 4
输出:“PINALSIGYAHRPI”
在这里插入图片描述

方法1(按行排序):
从左到右迭代 s s s,将每个字符添加到合适的行。
时间复杂度: O ( n ) O(n) O(n),空间复杂度: O ( n ) O(n) O(n)

class Solution:
    def convert(self, s: str, numRows: int) -> str:
        if numRows == 1:
            return s
        convStr = ""
        result = ["" for _ in range(numRows)]
        for index, char in enumerate(s):
            subIndex = index % (2 * numRows - 2)
            if subIndex < numRows:
                result[subIndex] += char
            else:
                result[2 * (numRows - 1) - subIndex] += char
        for each in result:
            convStr += each
        return convStr

方法2(按行访问):
首先访问行0中的所有字符,接着访问行1,然后行2,依此类推…
对于所有整数 k k k

  • 行0中的字符位于索引 k ( 2 n u m R o w s − 2 ) k(2numRows- 2) k(2numRows2)处;
  • n u m R o w s − 1 numRows−1 numRows1中的字符位于索引 k ( 2 n u m R o w s − 2 ) + n u m R o w s − 1 k(2numRows−2)+numRows−1 k(2numRows2)+numRows1处;
  • 内部的行 i i i中的字符位于索引 k ( 2 n u m R o w s − 2 ) + i k(2numRows−2)+i k(2numRows2)+i以及 ( k + 1 ) ( 2 n u m R o w s − 2 ) − i (k+1)(2numRows−2)−i (k+1)(2numRows2)i处;

时间复杂度: O ( n ) O(n) O(n),空间复杂度: O ( n ) O(n) O(n)

class Solution:
    def convert(self, s: str, numRows: int) -> str:
        if numRows == 1:
            return s
        convStr = ""
        lens=len(s)
        cycleLen =2*numRows-2
        for i in range(numRows):
            for j in range(0,lens-i,cycleLen):
                convStr+=s[j+i]
                if (i!=0 and i!=numRows-1 and j+cycleLen-i<lens):
                    convStr+=s[j+cycleLen-i]
        return convStr

7.整数反转

难度:简单
给你一个 32 位的有符号整数 x ,返回将 x 中的数字部分反转后的结果。
如果反转后整数超过 32 位的有符号整数的范围 [ − 2 31 , 2 31 − 1 ] [−2^{31}, 2^{31} − 1] [231,2311] ,就返回 0。
假设环境不允许存储 64 位整数(有符号或无符号)。

示例1:
输入:x = 123
输出:321
示例2:
输入:x = -123
输出:-321
示例3:
输入:x = 120
输出:21
示例4:
输入:x = 1534236469
输出:0

方法1(转字符串):
但用到了64位整数。
时间复杂度: O ( n ) O(n) O(n),空间复杂度: O ( n ) O(n) O(n)

class Solution:
    def reverse(self, x: int) -> int:
        string=str(abs(x))
        string=string[::-1]
        revNum=int(string)
        if revNum>2**31:return 0
        return -revNum if x<0 else revNum

方法2(数学):
r e v rev rev为翻转后的数字,为完成翻转,我们可以

// 弹出 x 的末尾数字 digit
digit = x % 10
x /= 10
// 将数字 digit 推入 rev 末尾
rev = rev * 10 + digit

我们需要在推入数字之前,判断是否满足
− 2 31 ≤ r e v ⋅ 10 + d i g i t ≤ 2 31 − 1 -2^{31}\le rev\cdot10+digit\le2^{31}-1 231rev10+digit2311
若该不等式不成立则返回 0 0 0
但是题目要求不允许使用64 位整数,上式改为
⌈ − 2 31 10 ⌉ ≤ r e v ≤ ⌊ 2 31 − 1 10 ⌋ 。 \left\lceil\frac{-2^{31}}{10}\right\rceil \leq r e v \leq\left\lfloor\frac{2^{31}-1}{10}\right\rfloor。 10231rev102311证明
时间复杂度: O ( n ) O(n) O(n),空间复杂度: O ( n ) O(n) O(n)

class Solution:
    def reverse(self, x: int) -> int:
        INT_MIN, INT_MAX = -2**31, 2**31 - 1
        rev = 0
        while x != 0:
            # INT_MIN 也是一个负数,不能写成 rev < INT_MIN // 10
            if rev < INT_MIN // 10 + 1 or rev > INT_MAX // 10:
                return 0
            digit = x % 10
            # Python3 的取模运算在 x 为负数时也会返回 [0, 9) 以内的结果,因此这里需要进行特殊判断
            if x < 0 and digit > 0:
                digit -= 10
            # 同理,Python3 的整数除法在 x 为负数时会向下(更小的负数)取整,因此不能写成 x //= 10
            x = (x - digit) // 10
            rev = rev * 10 + digit
        return rev

8. 字符串转换整数 (atoi)

难度:中等

请你来实现一个 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
示例2:
输入:s = "     -42"
输出:-42
示例3:
输入:s = “4193 with words”
输出:4193
示例4:
输入:s = “words and 987”
输出:0
示例5:
输入:s = “-91283472332”
输出:-2147483648

方法1(暴力求解):
时间复杂度: O ( n ) O(n) O(n),空间复杂度: O ( 1 ) O(1) O(1)

class Solution:
    def myAtoi(self, s: str) -> int:
        maxs = (1 << 31) - 1
        mins = -1 * (1 << 31)
        s = s.lstrip()
        kun = len(s)
        ints = 0
        i = 0
        k = 0
        if kun != 0:
            if s[i] == '+':
                k = 1
                i = i + 1
            elif s[i] == '-':
                k = -1
                i = i + 1
            else:
                k = 1
        while i < kun:
            if (s[i] < '0') or (s[i] > '9'):
                return max(min(ints, maxs), mins)
            ints = ints * 10 + k * (int(s[i]))
            i = i + 1
        return max(min(ints, maxs), mins)

方法2(有限自动机):
我们的程序在每个时刻有一个状态 s,每次从序列中输入一个字符 c,并根据字符 c 转移到下一个状态 s’。这样,我们只需要建立一个覆盖所有情况的从 s 与 c 映射到 s’ 的表格即可解决题目中的问题。
在这里插入图片描述
我们可以用下面的表格来表示这个自动机:

 ’ ’+/-numberother
startstartsignedin_numberend
signedendendin_numberend
in_numberendendin_numberend
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

方法3(正则表达式):

import re
class Solution:
    def myAtoi(self, s: str) -> int:
        return max(min(int(*re.findall('^[\+\-]?\d+', s.lstrip())), 2**31 - 1), -2**31)

9. 回文数

难度:简单
给你一个整数 x ,如果 x 是一个回文整数,返回 true ;否则,返回 false 。
回文数是指正序(从左向右)和倒序(从右向左)读都是一样的整数。例如,121 是回文,而 123 不是。

  • − 2 31 ≤ x ≤ 2 31 − 1 -2^{31} \le x \le 2^{31} - 1 231x2311

示例1:
输入:x = 121
输出:true
示例2:
输入:x = -121
输出:false
示例3:
输入:x = 10
输出:false

方法1(转字符串):
时间复杂度: O ( n ) O(n) O(n),空间复杂度: O ( n ) O(n) O(n)

class Solution:
    def isPalindrome(self, x: int) -> bool:
        if x<0:return False
        s=str(x)
        return s[::-1]==s

方法2(反转一半数字):
时间复杂度: O ( l o g n ) O(log n) O(logn),空间复杂度: O ( 1 ) O(1) O(1)

class Solution:
    def isPalindrome(self, x: int) -> bool:
        if x < 0 or (x % 10 == 0 and x != 0):
            return False
        revertedNumber = 0
        while x > revertedNumber:
            revertedNumber = revertedNumber * 10 + x % 10
            x //= 10
        return x == revertedNumber or x == revertedNumber // 10

10. 正则表达式匹配

难度:困难
给你一个字符串 s 和一个字符规律 p,请你来实现一个支持 ‘.’ 和 ‘ ∗ \ast ’ 的正则表达式匹配。

  • ‘.’ 匹配任意单个字符
  • ∗ \ast ’ 匹配零个或多个前面的那一个元素

所谓匹配,是要涵盖 整个 字符串 s的,而不是部分字符串。

示例1:
输入:s = “aa” p = “a”
输出:false
示例2:
输入:s = “aa” p = “a ∗ \ast
输出:true
示例3:
输入:s = “ab” p = “. ∗ \ast
输出:true
示例4:
输入:s = “aab” p = “c ∗ \ast a ∗ \ast b”
输出:true
示例5:
输入:s = “mississippi” p = “mis ∗ \ast is ∗ \ast p ∗ \ast .”
输出:false

import re
class Solution:
    def isMatch(self, s: str, p: str) -> bool:
        return s in re.findall(p,s)

方法1(动态规划):
字母 + 星号的组合在匹配的过程中,本质上只会有两种情况:

  • 匹配 s 末尾的一个字符,将该字符扔掉,而该组合还可以继续进行匹配;
  • 不匹配字符,将该组合扔掉,不再进行匹配。

状态转移方程:
f [ 0 ] [ 0 ] = t r u e , f [ i ] [ j ] = {  if  ( p [ j ] ≠ ′ ∗ ′ ) = { f [ i − 1 ] [ j − 1 ] ,  matches  ( s [ i ] , p [ j ] )  false,   otherwise   otherwise  = { f [ i − 1 ] [ j ]  or  f [ i ] [ j − 2 ] ,  matches  ( s [ i ] , p [ j − 1 ] ) f [ i ] [ j − 2 ] ,  otherwise  \begin{array}{ll} f[0][0]=&true,\\ f[i][j]=&\left\{\begin{array}{ll} \text { if }\left(p[j] \neq^{'\ast'}\right) & = \left\{\begin{array}{ll} f[i-1][j-1], & \text { matches }(s[i], p[j]) \\ \text { false, } & \text { otherwise } \\ \end{array}\right.\\ \text { otherwise }& = \left\{\begin{array}{ll} f[i-1][j] \text { or } f[i][j-2], & \text { matches }(s[i], p[j-1])\\ f[i][j-2],& \text { otherwise } \end{array}\right. \end{array}\right.\\ \end{array} f[0][0]=f[i][j]=true, if (p[j]=) otherwise ={f[i1][j1], false,  matches (s[i],p[j]) otherwise ={f[i1][j] or f[i][j2],f[i][j2], matches (s[i],p[j1]) otherwise 
其中 matches ( x , y ) \text {matches}(x, y) matches(x,y)判断两个字符是否匹配的辅助函数。只有当 y 是 . 或者 x 和 y 本身相同时,这两个字符才会匹配。

时间复杂度: O ( m n ) O(mn) O(mn),空间复杂度: O ( m n ) O(mn) O(mn)

class Solution:
    def isMatch(self, s: str, p: str) -> bool:
        m, n = len(s), len(p)

        def matches(i: int, j: int) -> bool:
            if i == 0:
                return False
            if p[j - 1] == '.':
                return True
            return s[i - 1] == p[j - 1]

        f = [[False] * (n + 1) for _ in range(m + 1)]
        f[0][0] = True
        for i in range(m + 1):
            for j in range(1, n + 1):
                if p[j - 1] == '*':
                    f[i][j] |= f[i][j - 2]
                    if matches(i, j - 1):
                        f[i][j] |= f[i - 1][j]
                else:
                    if matches(i, j):
                        f[i][j] |= f[i - 1][j - 1]
        return f[m][n]

LeetCode1-5

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值