Given a singly linked list, determine if it is a palindrome.
Follow up:
Could you do it in O(n) time and O(1) space?
要求O ( n ) 的时间和固定的空间。
数组因为有index可以直接访问,判断是否回文是简单的,那么链表怎么访问到头,尾部呢?
我们的一个想法是:将链表翻转,要是翻转后的链表跟原链表的对应元素值都是一样的,就可以了。
但这又带来另一个问题。翻转链表会破坏原来链表的结构!
又因为空间的限制,我们不可能再创建一个链表。
所以怎么办呢?
将链表的一半翻转!
比如 1 -> 2 -> 2 -> 1
我们找出后半部分的head, 2 - > 1, 翻转这部分,再跟原来链表的头进行比较就可以了!
1 -> 2 -> 3 -> 2 -> 1 , 对于奇数的情况,翻转 2 -> 1这后半部分。
如何走到链表的中部,靠一次走一步的slow指针,和一次走两步的fast指针实现。
运行效率:
代码:
public class PalindromeLinkedList {
public boolean isPalindrome(ListNode head) {
ListNode fast = head, slow = head;
ListNode rightHead = null;
while (fast != null && fast.next != null) {
slow = slow.next;
fast = fast.next.next;
}
if (fast == null) { // even
rightHead = reverseListIterative(slow);
} else {// odd
rightHead = reverseListIterative(slow.next);
}
while (rightHead != null) {
if (head.val != rightHead.val) {
return false;
}
head = head.next;
rightHead = rightHead.next;
}
return true;
}
private ListNode reverseListIterative(ListNode head) {
if (head == null || head.next == null) {
return head;
}
ListNode fakeNode = new ListNode(-1);
fakeNode.next = head;
ListNode cur = head.next, pre= head;
while (cur != null) {
pre.next = pre.next.next;
cur.next = fakeNode.next;
fakeNode.next = cur;
cur = pre.next;
}
return fakeNode.next;
}
}