LeetCode回文链表 双指针+反转链表

234. 回文链表

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

示例 1:

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

示例 2:

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

思路:

  要判断链表是否是回文链表,我们自然是希望可以用两个指针,一个从前向后走,另一个从后向前走,然后逐一比较直到两个指针相遇了。

  然而,链表不是数组,怎么可以从后向前遍历呢?但没关系,没有条件我们可以创造条件——我们原来做过反转链表的题目,我们可以把链表的后半段进行反转,这样我们对反转的链表进行遍历,就相当于从后往前对原链表进行遍历了。

  那怎么反转链表的后半段呢?是不是只要找到链表的中间节点,交给我们定义的反转链表函数就好了。那怎么找到链表的中间节点呢?原来我们对链表进行归并排序时也用过:用快慢指针呀!

  没想到短短的一个题,用到了之前做题用过的很多常见技巧,算是一个复习综合题了~

  虽然总体思路有了,但写起代码来还是有很地方需要注意的。比如找后半段链表的时候,根据原链表自身长度的奇偶会有不同,需要自己处理一下,主要是因为奇数链表的中间结点我们是不考虑的

  因为right判断终点的条件是while(right and right.next),假如right最后是终止在节点处,则链表是奇数个,left需要取下一个,当成后半段的头结点,再次强调是这是因为奇数链表的中间结点我们是不考虑的;假如right最后是终止在节点后的None处,则链表是偶数个,left不用动,就是后半段的头结点。

代码:

class Solution(object):

    def isPalindrome(self, head):

        def reverse(head):#经典 非递归法反转链表 具体细节就不写注释了 有专门的题

            pre=None

            cur=head

            nex=None

            while(cur):

                nex = cur.next

                cur.next=pre

                pre = cur

                cur=nex

            return pre

        left=head#定义快慢指针 left和right

        right=head

        while(right and right.next):#假如快指针到头

            left=left.next

            right=right.next.next

        if right!=None:# right最后不为空 链表长是奇数 left要变成下一个

            left=left.next

        ch = reverse(left)#对后半段反转

        while ch:#对后半段元素逐一和前半段比较

            if head.val!=ch.val:#一旦有元素不同就不是回文链表

                return False#直接返回

            head=head.next

            ch=ch.next

        return True#若能顺利遍历结束,则是回文链表

小结:

  代码中的反转链表我就用的之前写过的非递归的迭代方法,这个基本上可以当成工具函数默写出来了。对于奇偶的判断我加了点图,应该就很好理解了(感觉画图还是个挺费时间的事~)。

  除了判断奇偶长度上有一点小特殊处理外,我们最后逐一比较的时候是用的while ch,这样就可以只考虑后半段的长度,也巧妙地把奇数情况下的中间节点忽略,也是一个简洁高效的写法。

posted @   JunanP  阅读(7)  评论(0编辑  收藏  举报  
相关博文:
阅读排行:
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· DeepSeek 开源周回顾「GitHub 热点速览」
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
点击右上角即可分享
微信分享提示