《算法通关之路》-chapter2回文的艺术

《算法通关之路》学习笔记,记录一下自己的刷题过程,详细的内容请大家购买作者的书籍查阅。

验证回文串 II

力扣第680题
给你一个字符串 s,最多 可以从中删除一个字符。
请你判断 s 是否能成为回文字符串:如果能,返回 true ;否则,返回 false 。

'''
解法一:双指针法
时间复杂度:O(n)
'''
class Solution:
    def validPalindrome(self, s: str) -> bool:
        l, r = 0, len(s)-1
        
        def isPalindrome(s: str) -> bool:
            l, r = 0, len(s)-1
            while l < r:
                if s[l] == s[r]:
                    l += 1
                    r -= 1
                else:
                    return False
            return True

        while l < r:
            if s[l] != s[r]:
                return isPalindrome(s[l+1 : r+1]) or isPalindrome(s[l : r])
            else:
                l += 1
                r -= 1
        return True

## 试运行
s = "abca"
solu = Solution()
solu.validPalindrome(s)

回文链表

力扣第234题
给你一个单链表的头节点 head ,请你判断该链表是否为回文链表。如果是,返回 true ;否则,返回 false 。

from typing import Optional

class ListNode:
    def __init__(self, val=0, next=None):
        self.val = val
        self.next = next

'''
解法一:链表(遍历1.5遍)->数组(长度为链表长度一半)
时间复杂度:O(n)
'''
class Solution:
    def isPalindrome(self, head: Optional[ListNode]) -> bool:
        length = 0
        p = head
        while p:
            p = p.next
            length += 1
        if length == 0 or length == 1:
            return True
        flag = False
        if length % 2:
            flag = True
        half_of_length = length // 2
        stack = []
        p = head
        while half_of_length :
            stack.append(p.val)
            p = p.next
            half_of_length -= 1
        if flag:
            p = p.next
        while p:
            if p.val == stack[-1]:
                p = p.next
                stack.pop()
            else: 
                return False
        return True
    
'''
解法二:链表(遍历1遍)->数组(长度为链表长度)
时间复杂度:O(n)
'''
class Solution:
    def isPalindrome(self, head: Optional[ListNode]) -> bool:
        def isPalindrome(s: str) -> bool:
            l, r = 0, len(s)-1
            while l < r:
                if s[l] == s[r]:
                    l += 1
                    r -= 1
                else:
                    return False
            return True

        p = head
        stack = list()
        while p:
            stack.append(p.val)
            p = p.next

        return isPalindrome(stack)

‘’’
反转链表
def reverseList(head: ListNode) -> ListNode:
if not head:
return None
prev = None
cur = head
while cur:
cur.next, prev, cur = prev, cur, cur.next
return prev
‘’’

'''
解法三:反转链表
时间复杂度:O(n),空间复杂度O(1)
'''
class Solution:
    def isPalindrome(self, head: Optional[ListNode]) -> bool:
        pre = None
        slow = fast = head
        while fast and fast.next:
            fast = fast.next.next # 先更新fast指针
            slow.next, pre, slow = pre, slow, slow.next
        if fast:
            slow = slow.next
        # pre向前遍历,slow向后遍历
        while slow:
            if slow.val != pre.val:
                return False
            pre = pre.next
            slow = slow.next
        return True

回文数

力扣第9题
给你一个整数 x ,如果 x 是一个回文整数,返回 true ;否则,返回 false 。
回文数是指正序(从左向右)和倒序(从右向左)读都是一样的整数。

'''
解法一:转化为字符串
时间复杂度:O(n)
'''
class Solution:
    def isPalindrome(self, x: int) -> bool:
        def isPalindrome(s: str) -> bool:
            l, r = 0, len(s)-1
            while l < r:
                if s[l] == s[r]:
                    l += 1
                    r -= 1
                else:
                    return False
            return True
        
        if x < 0:
            return False
        x = str(x)
        return isPalindrome(x)

## 试运行
x = -121
solu = Solution()
solu.isPalindrome(x)
'''
解法二:求余
时间复杂度:O(n)
'''
class Solution:
    def isPalindrome(self, x: int) -> bool:
        if x < 0:
            return False
        if x  == 0:
            return True
        if x % 10 == 0:
            return False

        copy = x
        res = 0
        while x != 0:
            res = (x % 10) + res * 10
            x = x // 10
        return res == copy
## 试运行
x = -121
solu = Solution()
solu.isPalindrome(x)

最长回文子串

力扣第5题
给你一个字符串 s,找到 s 中最长的回文子串。
如果字符串的反序与原始字符串相同,则该字符串称为回文字符串。

'''
解法一:暴力法(超时)
时间复杂度:O(n3)
'''
class Solution:
    def longestPalindrome(self, s: str) -> str:
        n = len(s)
        res = ''

        def isPalindrome(s: str) -> bool:
            l, r = 0, len(s)-1
            while l < r:
                if s[l] == s[r]:
                    l += 1
                    r -= 1
                else:
                    return False
            return True
        
        for l in range(n):
            for r in range(l, n):
                if isPalindrome(s[l:r+1]) and r - l + 1 > len(res):
                    res = s[l:r+1]
        return res

# 试运行
s = "babad"
solu = Solution()
solu.longestPalindrome(s)
'''
解法一:中心扩展法
时间复杂度:O(n2)
'''
class Solution:
    def longestPalindrome(self, s: str) -> str:
        n = len(s)
        res = ''

        def extend(s: str, i: int, j: int):
            while i >= 0 and j < n and s[i] == s[j]:
                i, j = i - 1, j + 1
            return s[i + 1 : j]
        
        for i in range(n):
            e1 = extend(s, i, i)
            e2 = extend(s, i, i + 1)
            if max(len(e1), len(e2)) > len(res):
                res = e1 if len(e1) > len(e2) else e2
        return res

# 试运行
s = "babad"
solu = Solution()
solu.longestPalindrome(s)

最长回文子序列

力扣第516题
给你一个字符串 s ,找出其中最长的回文子序列,并返回该序列的长度。
子序列定义为:不改变剩余字符顺序的情况下,删除某些字符或者不删除任何字符形成的一个序列。

'''
解法一:动态规划
时间复杂度:O(n2)
'''
class Solution:
    def longestPalindromeSubseq(self, s: str) -> int:
        n = len(s)
        dp = [[0] * n for i in range(n)]
        for i in reversed(range(n)):
            for j in range(i, n):
                if i == j:
                    dp[i][j] = 1
                elif s[i] == s[j]:
                    dp[i][j] = dp[i + 1][j - 1] + 2
                else:
                    dp[i][j] = max(dp[i + 1][j], dp[i][j - 1])                                                       
        return dp[0][n-1]

# 试运行
s = "bbbab"
solu = Solution()
solu.longestPalindromeSubseq(s)

超级回文数

力扣第906题
如果一个正整数自身是回文数,而且它也是一个回文数的平方,那么我们称这个数为超级回文数。
现在,给定两个正整数 L 和 R (以字符串形式表示),返回包含在范围 [L, R] 中的超级回文数的数目。

'''
解法一:暴力法(超时)
'''
import math
class Solution:
    def superpalindromesInRange(self, left: str, right: str) -> int:
        cnt = 0

        def isPalindrome(s: str) -> bool:
            l, r = 0, len(s)-1
            while l < r:
                if s[l] == s[r]:
                    l += 1
                    r -= 1
                else:
                    return False
            return True
        
        for i in range(math.floor(int(left) ** 0.5), math.ceil(int(right) ** 0.5)):
            if isPalindrome(str(i)) and isPalindrome(str(i ** 2)):
                cnt += 1
        return cnt

# 试运行
left, right = "4", "1000"
solu = Solution()
solu.superpalindromesInRange(left, right)
'''
解法二:构造回文数
'''
import math
class Solution:
    def superpalindromesInRange(self, left: str, right: str) -> int:
        cnt = 0

        def isPalindrome(s: str) -> bool:
            l, r = 0, len(s)-1
            while l < r:
                if s[l] == s[r]:
                    l += 1
                    r -= 1
                else:
                    return False
            return True

        i = 1
        while i < 10 ** 5:
            power = math.floor(math.log10(i))
            x = i
            r = 0 # r是倒序的i
            while x > 0:
                r = r * 10 + (x % 10)
                x = x // 10
            Q = (i * 10 ** power + r % 10 ** power) ** 2 # 12321

            if Q > int(right):
                return cnt

            if Q >= int(left) and isPalindrome(str(Q)):
                cnt += 1
            Q = (i * 10 ** (power + 1) + r) ** 2 # 123321
            if int(left) <= Q <= int(right) and isPalindrome(str(Q)):
                cnt += 1
            i += 1
        return cnt

# 试运行
left, right = "4", "1000"
solu = Solution()
solu.superpalindromesInRange(left, right)

github笔记本

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Jiawen9

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值