Description
Given a singly linked list, determine if it is a palindrome.
class ListNode {
int val;
ListNode next;
ListNode(int x) { val = x; }
}
Example
Example 1:
Input: 1->2
Output: false
Example 2:
Input: 1->2->2->1
Output: true
Solution
如果允许用额外空间的话,我们可以使用一个栈来逆序存储所有链表节点,之后再遍历链表并与栈中取出的节点作比较。这种思路的代码如下:
class Solution {
public boolean isPalindrome(ListNode head) {
if(head == null)
return true;
ListNode node = head;
Stack<Integer> stack = new Stack<>();
while(node != null){
stack.push(node.val);
node = node.next;
}
node = head;
while(node != null){
Integer last = stack.pop();
if(node.val != last) return false;
node = node.next;
}
return true;
}
}
但这种解法不是最优的,应该尝试寻找更优的解法。判断一个链表是否为回文链表,我们就是要将链表分成两段,从段头到段中的每个节点都要与从段尾到段中的每个节点相同。举个例子,链表1->2->2->1
可以先切断为1->2
和2->1
,然后再将第二段2->1
反转成1->2
,之后就可以与第一段1->2
逐个节点进行比较。
这里的问题就是如何快速找到链表的中间节点。如果是数组结构的话,我们可以很快的通过下标定位找到,但是链表无法利用这一特性。因此,我们可以使用快慢两个指针,快指针比慢指针快一步,因此当快指针到达链表末尾的时候,慢指针正好指向链表的正中间,这样便找到了中间节点。
class Solution {
public boolean isPalindrome(ListNode head) {
ListNode fast = head, slow = head;
while (fast != null && fast.next != null) {
fast = fast.next.next;
slow = slow.next;
}
if (fast != null) {
slow = slow.next;
}
slow = reverseList(slow);
fast = head;
while (slow != null) {
if (fast.val != slow.val) {
return false;
}
fast = fast.next;
slow = slow.next;
}
return true;
}
public ListNode reverseList(ListNode head) {
if(head == null || head.next == null)
return head;
ListNode tail = reverseList(head.next);
head.next.next = head;
head.next = null;
return tail;
}
}