240
生活,简单就好!

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编程题汇总(持续更新中……)

posted @ 2022-01-23 09:59  wintest  阅读(187)  评论(0编辑  收藏  举报