剑指 Offer II 027. 回文链表

给定一个链表的 头节点 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;
    }
}

结果如下:

你可能感兴趣的:(剑指 Offer II 027. 回文链表)