Java每日一题——>剑指 Offer II 027. 回文链表
Posted stormzhuo
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java每日一题——>剑指 Offer II 027. 回文链表相关的知识,希望对你有一定的参考价值。
这是LeetCode上的 [027,回文链表],难度为 [简单]
题目
给定一个链表的 头节点 head ,请判断其是否为回文链表。
如果一个链表是回文,那么链表节点序列从前往后看和从后往前看是相同的。
示例 1
输入: head = [1,2,3,3,2,1]
输出: true
示例 2:
输入: head = [1,2]
输出: false
题解(快慢指针,反转)
思路分析
回文链表有个特点就是对称性,即链表的第一个结点的值和最后一个结点的值相等,以此类推。因此我们可以把链表从中间划分为两个链表,然后把前一段链表或者后一段链表反转,最后同时遍历两链表,遍历过程中比较两结点的值,若不相等,则不是回文链表,否则是回文链表
需要注意的是,题意只让我们判断链表是否是回文链表,所以我们不能改变原有链表的结构,而反转链表需要尾结点的下一个结点为null,即我们不能把前一段链表进行反转(前一段链表反转需要断开链表,即尾结点需要指向null),只能把后一段链表反转(它的尾节点是指向null的),总的来说是逻辑上划分为两个链表,并不在物理结构上断开链表
步骤
第一步(把链表在逻辑结构上从中间划分为两个链表)
要想在逻辑结构上从中间划分为两个链表,需要求后一段链表的头结点,下面分为两种情况讨论
- 当链表长度为偶数时,链表关于中间链对称,需要从中间链中断开(逻辑结构,实际不断开),因此需要求前一段链表的尾结点,尾结点的下一个结点即为后一段链表的头结点
- 当链表长度为奇数时,链表关于中间结点对称,需要从中间结点的左右链中断开(中间结点是共用的,所以不用比较),因此需要求链表的中间结点,中间结点的下一个结点就是后一段链表的头结点
综上,我们可以使用快慢指针来求链表的中间结点,由于当链表为偶数时,需要求前一段链表的尾结点,因此逻辑(循环终止条件)会和求中间结点稍有不同
第二步(反转后一段链表)
第三步(同时遍历两链表,比较结点值)
第四步(再次反转后一段链表,恢复原有结构)
代码实现
public class Solution
public boolean isPalindrome(ListNode head)
/* 当链表为偶数时,返回前一段链表的尾结点,尾结点的下一个结点为后一段链表的头结点
* 当链表为奇数时,返回链表的中间结点,中间结点的下一个结点为后一段链表的头结点*/
ListNode firstHalfEndOrMiddleNode = EndOrMiddleNode(head);
// 返回后一段链表的头结点
ListNode secondHalfHead = firstHalfEndOrMiddleNode.next;
Boolean aBoolean = equals(head, reverseList(secondHalfHead));
// 恢复原有结构
reverseList(secondHalfHead);
return aBoolean;
public ListNode EndOrMiddleNode(ListNode head)
ListNode slow = head;
ListNode fast = head;
/* 当链表长度为偶数时,终止条件为fast在链表倒数第二个结点时终止,即它的下下结点为null
* 此时slow在前一段链表的的尾结点
* 当链表长度为奇数时,终止条件为fast在链表的尾结点时终止,即它的下一个结点为null
* 此时slow在链表的中间结点*/
while (fast.next != null && fast.next.next != null)
slow = slow.next;
fast = fast.next.next;
return slow;
public ListNode reverseList(ListNode head)
ListNode currNode = head;
ListNode preNode = null;
while (currNode != null)
ListNode nextNode = currNode.next;
currNode.next = preNode;
preNode = currNode;
currNode = nextNode;
return preNode;
public Boolean equals(ListNode head1, ListNode head2)
while (head2 != null)
if (head1.val != head2.val)
return false;
head1 = head1.next;
head2 = head2.next;
return true;
复杂度分析
假设l链表长度为n
时间复杂度:
最初需要遍历把链表划分为两半,时间复杂度为O(n),在反转后一段链表时,时间复杂度为O(n/2),最后同时遍历两链表时,时间复杂度为O(n/2),故总的时间复杂度为O(n) + 2O(n/2) = O(n)
空间复杂度:
只声明了几个固定的结点,故空间复杂度为O(1)
以上是关于Java每日一题——>剑指 Offer II 027. 回文链表的主要内容,如果未能解决你的问题,请参考以下文章
Java每日一题——>剑指 Offer II 035. 最小时间差(三解,蛮力,排序,哈希)
Java每日一题——> 剑指 Offer II 028. 展平多级双向链表
Java每日一题——>剑指 Offer II 027. 回文链表
Java每日一题——>剑指 Offer II 030. 插入删除和随机访问都是 O 的容器