Given a singly linked list, determine if it is a palindrome.

Example 1:

Input: 1->2
Output: false

Example 2:

Input: 1->2->2->1
Output: true

Follow up:
Could you do it in O(n) time and O(1) space?

回文链表。题意是给一个链表,判断是不是回文链表。思路是快慢指针找到链表中点,reverse后半段,然后比较前半和后半。题目要求不能使用额外空间,其实是不太可能的,除非直接在input的链表上做操作。

二刷的时候有一个疑问,找到的链表中点,如果整个链表的节点数为奇数,中点在哪?节点数为偶数,中点又在哪?我跑了一个例子帮助加强记忆,如下图,图中数字表示节点的index。当找中间节点的函数跑完的时候,如果节点数是偶数个,则s停在3的位置;如果节点数是奇数个,则s停在2的位置。后半部分的head节点是slow.next所以后半部分的head节点分别是4和3(偶数,奇数)。

reverse后半部分,则对于第一个例子,比较的是123和654两个链表;对于第二个例子,比较的是12和543两个链表。又因为while循环的时候判断的是两个链表同时不为空,所以当链表节点个数为奇数的时候,也能判断input是否为回文链表。

1 - 2 - 3 - 4 - 5 - 6

s    f

1 - 2 - 3 - 4 - 5

s    f

时间O(n) - 题目要求

空间O(1) - 题目要求

JavaScript实现

 1 /**
 2  * @param {ListNode} head
 3  * @return {boolean}
 4  */
 5 var isPalindrome = function(head) {
 6     if (head === null) return true;
 7     let middle = findMiddle(head);
 8     middle.next = reverse(middle.next);
 9 
10     let p = head;
11     let q = middle.next;
12     while (p !== null && q !== null) {
13         if (p.val !== q.val) {
14             return false;
15         }
16         p = p.next;
17         q = q.next;
18     }
19     return true;
20 };
21 
22 var findMiddle = function(head) {
23     let slow = head;
24     let fast = head.next;
25     while (fast !== null && fast.next !== null) {
26         slow = slow.next;
27         fast = fast.next.next;
28     }
29     return slow;
30 }
31 
32 var reverse = function(head) {
33     let pre = null;
34     while (head !== null) {
35         let next = head.next;
36         head.next = pre;
37         pre = head;
38         head = next;
39     }
40     return pre;
41 }

最后注意代码里面24行定义fast pointer的方式。

 

Java实现

 1 /**
 2  * Definition for singly-linked list.
 3  * public class ListNode {
 4  *     int val;
 5  *     ListNode next;
 6  *     ListNode(int x) { val = x; }
 7  * }
 8  */
 9 class Solution {
10     public boolean isPalindrome(ListNode head) {
11         // corner case
12         if (head == null) {
13             return true;
14         }
15         // normal case
16         ListNode middle = findMiddle(head);
17         middle.next = reverse(middle.next);
18         ListNode p1 = head;
19         ListNode p2 = middle.next;
20         while (p1 != null && p2 != null) {
21             if (p1.val != p2.val) {
22                 return false;
23             } else {
24                 p1 = p1.next;
25                 p2 = p2.next;
26             }
27         }
28         return true;
29     }
30 
31     private ListNode findMiddle(ListNode head) {
32         ListNode slow = head;
33         ListNode fast = head;
34         while (fast.next != null && fast.next.next != null) {
35             slow = slow.next;
36             fast = fast.next.next;
37         }
38         return slow;
39     }
40 
41     private ListNode reverse(ListNode head) {
42         ListNode pre = null;
43         while (head != null) {
44             ListNode next = head.next;
45             head.next = pre;
46             pre = head;
47             head = next;
48         }
49         return pre;
50     }
51 }

 

相关题目

125. Valid Palindrome

234. Palindrome Linked List

680. Valid Palindrome II

LeetCode 题目总结