《算法通关之路》学习笔记,记录一下自己的刷题过程,详细的内容请大家购买作者的书籍查阅。
验证回文串 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)