题目:

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

示例 1:

img

输入:head = [1,2,2,1]
输出:true

示例 2:

img

输入:head = [1,2]
输出:false

提示:

  • 链表中节点数目在范围[1, 105] 内

  • 0 <= Node.val <= 9


思路如下:

        这道题要判断一个链表是不是回文数,直观的判断方法为:将链表的后半段反转。然后将反转后的链表与前半段未反转的链表做比较,直到中间节点如果对应相同,则为回文数。

        因此重点在于如何找到后半段要反转的链表,这里我们采用之前学习的快慢指针方法,slow 所指的节点即为中间节点,之后则为后半段链表。接着将后半段链表反转,最后进行比较即可。


题解如下:

​
# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, val=0, next=None):
#         self.val = val
#         self.next = next
class Solution:
    def isPalindrome(self, head: Optional[ListNode]) -> bool:
        # 使用快慢指针找到链表的中点
        slow = fast = head
        pre = None
        # 快指针每次走两步,慢指针每次走一步,当快指针走到末尾时,慢指针刚好在中间
        while fast and fast.next:
            slow = slow.next
            fast = fast.next.next
        
        # 反转链表的后半部分
        while slow:
            temp = slow.next  # temp 指向当前节点的下一个节点
            pre = slow        # 将当前节点作为反转后的链表的 头节点 
            slow = temp       # 慢指针移动到下一个节点
        
        # 比较反转后的后半部分和前半部分是否相同
        while pre:
            if pre.val != head.val:
                return False
            pre = pre.next    # 移动反转后的链表指针
            head = head.next  # 移动原链表的指针
​
        return True

题解示例:


初始链表
链表结构为:1 -> 2 -> 3 -> 2 -> 1
​
# 找到链表中点 #
初始化指针:
slow 和 fast 都指向头节点 1。
pre 初始化为 None。
​
第一次循环:
fast 和 fast.next 都存在(fast 指向 1,fast.next 指向 2)。
slow 移动到下一个节点 2。
fast 移动两步到节点 3。
​
第二次循环:
fast 和 fast.next 都存在(fast 指向 3,fast.next 指向 2)。
slow 移动到下一个节点 3。
fast 移动两步到节点 1。
​
第三次循环:
fast.next 不存在(fast 指向 1,fast.next 为 None)。
循环结束。
此时,slow 指向节点 3,fast 指向节点 1。
​
# 反转后半部分链表 #
初始化:
slow 指向节点 3。
pre 为 None。
​
第一次循环:
temp = slow.next:temp 被赋值为 slow.next,即节点 2。
pre = slow:pre 指向节点 3。
slow = temp:slow 移动到节点 2。
​
第二次循环:
temp = slow.next:temp 被赋值为 slow.next,即节点 1。
pre = slow:pre 指向节点 2。
slow = temp:slow 移动到节点 1。
​
第三次循环:
temp = slow.next:temp 被赋值为 slow.next,即 None。
pre = slow:pre 指向节点 1。
slow = temp:slow 变为 None。
​
此时,反转后的后半部分链表为 1 -> 2 -> 3,pre 指向节点 1。
​
# 比较前后两部分链表#
初始化:
pre 指向节点 1。
head 指向原链表的头节点 1。
​
第一次循环:
比较 pre.val 和 head.val:1 == 1,相等。
pre 移动到下一个节点 2。
head 移动到下一个节点 2。
​
第二次循环:
比较 pre.val 和 head.val:2 == 2,相等。
pre 移动到下一个节点 3。
head 移动到下一个节点 3。
​
第三次循环:
比较 pre.val 和 head.val:3 == 3,相等。
pre 移动到下一个节点 None。
head 移动到下一个节点 None。
​
循环结束:
当 pre 变为 None 时,循环结束。所有比较都通过,函数返回 True,表示该链表是回文的。​

逻辑梳理:

  1. 找到链表中点:

    • 使用快慢指针法,快指针(fast)每次移动两步,慢指针(slow)每次移动一步。当快指针到达链表末尾时,慢指针刚好到达链表的中间位置。

  2. 反转后半部分链表:

    • 从中间节点开始,逐个将节点从原链表中取出,并将其插入到新链表的头部,从而实现反转。

  3. 比较前后两部分链表:

    • 将反转后的后半部分链表与原链表的前半部分逐个节点比较,如果所有对应节点的值都相等,则链表是回文的;否则不是。

Logo

北京人形旗下天工造物具身智能开源社区,聚焦具身天工与慧思开物两大平台

更多推荐