• LeetCode 5. 6. 题


    5.最长回文子串

            给你一个字符串 s,找到 s 中最长的回文子串。

    暴力解法:

    • 枚举出s的所有子串的左下标值和其长度
    • 判断字串是否是回文字串
    • 截取子串(begin:begin+maxLen)

            第2,3步在算法中都类似,重要的是怎么简化第1步。

    1. class Solution(object):
    2. def longestPalindrome(self, s):
    3. """
    4. :type s: str
    5. :rtype: str
    6. """
    7. # 判断 回文子串 的算法
    8. def validPalindromic(s,left,right):
    9. while left < right:#逐个比较左右侧值是否相等
    10. if s[left]!=s[right]:
    11. return False
    12. left+=1
    13. right-=1
    14. return True
    15. n = len(s)
    16. # 判断长度为1的字符串
    17. if n<2:
    18. return s
    19. maxLen = 1
    20. begin = 0
    21. #枚举 所有长度严格大于1的字串,p[i...j]
    22. for i in range(n-1):#右边界前一位
    23. for j in range(1,n):#左边界后一位
    24. if (j-i+1 > maxLen and validPalindromic(s,i,j)):
    25. maxLen = j-i+1 #子串长度递增
    26. begin = i #左边界右移
    27. return s[begin:begin+maxLen]

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

    中心扩展算法:从中心考虑

    • 将第1步简化为:枚举出所有中心字符串的中心位置和长度,需考虑子串长度为奇数、偶数的情况
    • 判断:在左侧向左移动,右侧向右移动,且左右端值相等时,该子串为回文子串
    1. class Solution(object):
    2. #中心扩散方法,判断是否为回文子串
    3. def expandAroundCenter(self, s,left,right):
    4. while left>=0 and right<len(s) and s[left] == s[right]:
    5. left-=1
    6. right+=1
    7. return left+1,right-1 #最后一步是条件不满足退出循环,所以下标值收缩一步
    8. def longestPalindrome(self, s):
    9. """
    10. :type s: str
    11. :rtype: str
    12. """
    13. start,end = 0,0
    14. for i in range(len(s)):
    15. left1,right1 = self.expandAroundCenter(s,i,i)#偶数回文子串
    16. left2,right2 = self.expandAroundCenter(s,i,i+1)#奇数回文子串
    17. if right1 - left1 > end-start:
    18. start,end = left1,right1
    19. if right2-left2 > end-start:
    20. start,end = left2,right2
    21. return s[start:end+1]

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

    动态规划:

            回文子串状态转移的性质:在左右字符相同的情况下,中间字符串决定了子串是否属于回文子串。

            例如一个字符串m:m[0]==m[3],且m[1:2]是回文序列,则m[1:3]是回文序列;m[2]==m[5],且m[3:4]不是回文序列,则m[2:5]不是回文序列。

             对于字符串的子串P(i,j),可以用如下表格记录子串是否是回文子串,根据表格可以看出,s[0:2]和s[1:3]都是回文子串。

    1. class Solution(object):
    2. def longestPalindrome(self, s):
    3. """
    4. :type s: str
    5. :rtype: str
    6. """
    7. n = len(s)
    8. if n<2:
    9. return s
    10. maxLen = 1
    11. begin = 0
    12. # 创建一个n*n的表格,初始化表格内容为False
    13. dp = [[False]*n for _ in range(n)]
    14. # 对角线元素都是回文子串
    15. for i in range(n):
    16. dp[i][i] = True
    17. # 枚举子串长度
    18. for L in range(2,n+1): #n=6,n+1=7,L=2,3,4,5,6
    19. for i in range(n):
    20. # 右边界j
    21. j = L+i-1
    22. if j>=n:
    23. break
    24. if s[i]!=s[j]:
    25. dp[i][j]=False
    26. else:
    27. if j-i<3:
    28. dp[i][j]=True
    29. else:
    30. dp[i][j]=dp[i+1][j-1]
    31. if dp[i][j] and j-i+1>maxLen:
    32. maxLen = j-i+1
    33. begin = i
    34. return s[begin:begin+maxLen]

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

    6.Z字形变换

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

    矩阵填充

    定义一个r*c的空矩阵,使用循环将s中的值以Z字型填入矩阵。输入字符串为 "PAYPALISHIRING" 行数为 3 时,排列如下:

    • 首先根据行数确定Z字变换的周期t,再求出行数c,这里的c比实际占用行数多一行
    • 遍历字符串s,当 s 下标 i 对周期 t 取余小于r-1时向下移动,否则向右上移动
    1. class Solution(object):
    2. def convert(self, s, numRows):
    3. """
    4. :type s: str
    5. :type numRows: int
    6. :rtype: str
    7. """
    8. n = len(s)
    9. if numRows < n:return s
    10. t = numRows * 2 - 2
    11. c = (n + t - 1) // t * (numRows - 1)
    12. mat = [[''] * c for _ in range(numRows)] #创建空矩阵,c列,numRows行
    13. x, y = 0, 0
    14. for i, ch in enumerate(s):
    15. mat[x][y] = ch
    16. if i % t < numRows - 1: #Z字移动的判断条件
    17. x += 1 # 向下移动
    18. else:
    19. x -= 1
    20. y += 1 # 向右上移动
    21. return ''.join(ch for row in mat for ch in row if ch) #取出非空字符

  • 相关阅读:
    排列组合——n个人平均分成m组
    【Java+SSM】电影院管理系统(电影院选座系统、在线电影购票系统)
    C进阶---自定义类型:结构体、枚举、联合
    Windows10安装配置allure
    h3c交换机配置教程命令(新手配置交换机详细教程)
    高等数值计算方法学习笔记第7章【非线性方程组求根】
    【21天学习挑战赛学习打卡】顺序查找
    百数应用中心——选择一款适合企业的标准应用
    java包装类
    Shell编程之函数与数组
  • 原文地址:https://blog.csdn.net/icecreamdinner/article/details/126242299