Python编程题47--回文链表
题目
给你一个单链表的头节点 head ,请你判断该链表是否为回文链表。如果是,返回 True ;否则,返回 False。
例如:
原链表转换为列表:[1, 2, 2, 1],返回结果:True
原链表转换为列表:[1, 2],返回结果:False
说明:
- 返回结果时,链表中各节点的指向需要和最开始保持一致。
已知 链表节点的定义、链表与列表相互转换 的代码如下:
class ListNode: # 单链表
def __init__(self, val=0, next=None):
self.val = val # 链表节点上存储的元素
self.next = next # 指向下一个链表节点
def list_to_list_node(numbers): # 将列表转换为单向链表,并返回链表的头节点
dummy_head = ListNode(0)
pre = dummy_head
for number in numbers:
pre.next = ListNode(number)
pre = pre.next
pre = dummy_head.next
return pre
def list_node_to_list(node): # 将单向链表转换为列表
result = []
while node:
result.append(node.val)
node = node.next
return result
实现思路1
- 将原链表中所有数据存储到一个列表中,然后再判断是否回文
- 判断列表是否回文,可以定义2个指针:left、right,一个从头开始往后移动,另一个从最后开始往前移动,每次判断指向的元素是否相同,如果不相同那么就说明不是回文,直接返回 False
代码实现1
class Solution:
def isPalindrome(self, head: ListNode) -> bool:
cur, length = head, 0
result = []
while cur is not None: # 遍历链表,把所有节点上的元素都存储到列表 result 中
length += 1
result.append(cur.val)
cur = cur.next
left, right = 0, length - 1 # 定义2个指针,一个从头开始往后,另一个从最后开始往前
while left < right:
if result[left] != result[right]: # 如果发现 left 和 right 对应的元素不一致,则说明不是回文
return False
left += 1
right -= 1
return True
- 时间复杂度:O(n)
- 空间复杂度:O(n)
当然,我们在上面把链表元素都存储到列表 result 后,也可以直接将列表与其反转后的列表进行比较,代码如下:
class Solution:
def isPalindrome(self, head: ListNode) -> bool:
cur = head
result = []
while cur is not None: # 遍历链表,把所有节点上的元素都存储到列表 result 中
result.append(cur.val)
cur = cur.next
return result == result[::-1]
实现思路2
- 使用
双指针
的方式来实现 - 从链表中找到中间节点,将链表分为2部分:前半部分、后半部分,前半部分从原链表的头节点到中间节点,后半部分则是从原链表中间节点的下一个节点到最后节点
- 反转原链表的后半部分,得到反转后的头节点 reverse_head
- 定义一个变量,用于标记最终判断结果,默认为True
- 遍历两个链表,前半部分链表从head开始移动,反转后半部分的链表从reverse_head开始移动,依次比较节点元素是否一致,如果不一致则将结果标记为 False ,同时 break 跳出循环
- 比较结束后,因为原链表被分割成了两部分,所以需要先恢复原链表的指向,最后再返回最终判断结果即可
代码实现2
class Solution:
def isPalindrome(self, head: ListNode) -> bool:
if head is None: # 如果是空链表,直接返回True
return True
middle_node = self.get_middle_node(head) # 找到中间节点
reverse_head = self.reverse_list_node(middle_node.next) # 从原链表中间节点的下一个节点到最后节点,进行反转,并返回反转后的头节点
flag, pre, post = True, head, reverse_head
while post is not None:
# 前半部分链表从head开始,后半部分反转后的链表从reverse_head开始,比较节点元素是否一致
if pre.val != post.val:
flag = False
break
pre = pre.next
post = post.next
middle_node.next = self.reverse_list_node(reverse_head) # 恢复原链表
return flag
def get_middle_node(self, head: ListNode) -> ListNode: # 找到链表的中间节点
slow, fast = head, head # 定义慢指针和快指针
while fast.next is not None and fast.next.next is not None:
slow = slow.next # 慢指针每次移动1位
fast = fast.next.next # 快指针每次移动2位
return slow
def reverse_list_node(self, head: ListNode) -> ListNode: # 反转链表, 返回反转后的头节点
pre, cur = None, head
while cur is not None:
next_node = cur.next
cur.next = pre
pre = cur
cur = next_node
return pre
- 时间复杂度:O(n)
- 空间复杂度:O(1)
更多Python编程题,等你来挑战:Python编程题汇总(持续更新中……)
作者:wintest
本文版权归作者和博客园共有,欢迎转载,但必须在文章页面明显位置给出原文链接,并保留此段声明,否则保留追究法律责任的权利。