Leetcode234. Palindrome Linked List
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?
解法一 快慢指针
找到链表的中间节点,反转后半链表的节点,之后与前链表半节点相比较。
快指针一次走两步,慢指针一次走一步,当快指针走到终点时,慢指针走到中点。
- 当链表结点个数为偶数,
slow
指向第二个练宝宝的开始 - 当链表结点个数为奇数,
slow
指向最终将的位置
1 -> 3 -> 1 拆成 1 和 1
1 -> 3 -> 5 ->5 -> 3 -> 1 拆成 1-> 3 -> 5 和 5 -> 3 -> 1
Java
public boolean isPalindrome(ListNode head) {
if (head == null || head.next == null) {
return true;
}
// 找中点,链表分成两个
ListNode slow = head;
ListNode fast = head;
while (fast != null && fast.next != null) {
slow = slow.next;
fast = fast.next.next;
}
// 第二个链表倒置
ListNode newHead = reverseList(slow);
// 前一半和后一半依次比较
while (newHead != null) {
if (head.val != newHead.val) {
return false;
}
head = head.next;
newHead = newHead.next;
}
return true;
}
private ListNode reverseList(ListNode head) {
if (head == null) {
return null;
}
ListNode tail = null;
while (head != null) {
ListNode temp = head.next;
head.next = tail;
tail = head;
head = temp;
}
return tail;
}
Python
def isPalindrome(self, head):
"""
:type head: ListNode
:rtype: bool
"""
fast = slow = head
# 找到中间节点
while fast and fast.next:
fast = fast.next.next
slow = slow.next
# 翻转后半部分
prev = None
while slow:
tmp = slow.next
slow.next = prev
prev = slow
slow = tmp
# 比较前后两部分
while prev: # while prev and head:
if prev.val != head.val:
return False
prev = prev.next
head = head.next
return True
最终状态
fast tmp
None prev slow
^ ^ ^
| | |
1 --> 2 --> 3 <-- 2 <-- 1 None
注意最后的while prev
不能换成while fast
, 因为这是总节点数为奇数的情况,如果是偶数情况就不一样了,如下:
tmp
slow
None prev fast
^ ^ ^
| | |
1 --> 2 --> 2 <-- 1 None
解法二 空间复杂度为O(n)
直接把List中元素拷贝到数组中直接比较
def isPalindrome(self, head):
vals = []
while head:
vals += head.val,
head = head.next
return vals == vals[::-1]