给定一个链表的 头节点 head ,请判断其是否为回文链表。
如果一个链表是回文,那么链表节点序列从前往后看和从后往前看是相同的。
示例 1:
输入: head = [1,2,3,3,2,1]
输出: true
示例 2:
输入: head = [1,2]
输出: false
提示:
链表 L 的长度范围为 [1, 105]
0 <= node.val <= 9
进阶:能否用 O(n) 时间复杂度和 O(1) 空间复杂度解决此题
来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/aMhZSa
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
解题思路及方法
用线性表按序存储每一个节点,然后用双指针比较是常规的办法,但是会用O(n)的空间。我们采用将链表后半部分反转,然后将前半部分后半部分对比值即可在O(1)的空间解决。
我们用快慢指针找到前半部分最后一个节点,如果链表长度为奇数则slow指向中间节点,为偶数指向前半部分节点的末尾节点。我们用mid = slow.next记录后半部分开头,然后反转后半部分链表,并对比值即可。
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode() {}
* ListNode(int val) { this.val = val; }
* ListNode(int val, ListNode next) { this.val = val; this.next = next; }
* }
*/
class Solution {
public boolean isPalindrome(ListNode head) {
if (head == null) return true;
// 快慢指针找中点
ListNode fast = head;
ListNode slow = head;
while (fast.next != null && fast.next.next != null) {
fast = fast.next.next;
slow = slow.next;
}
// 反转后半部分链表
ListNode mid = reverse(slow.next);
ListNode pt1 = mid;
ListNode pt2 = head;
boolean res = true;
while (res && pt1 != null) {
if (pt1.val != pt2.val) res = false;
pt1 = pt1.next;
pt2 = pt2.next;
}
// 恢复链表
slow.next = reverse(mid);
return res;
}
public ListNode reverse(ListNode head) {
ListNode prev = null;
ListNode curr = head;
while (curr != null) {
ListNode next = curr.next;
curr.next = prev;
// 移动指针
prev = curr;
curr = next;
}
return prev;
}
}
结果如下: