题目描述(简单难度)

判断一个链表存储的数字是否是回文数字。
思路分析
这个题就难在链表不能随机读取,不能像数组那样直接首尾首尾的依次判断。如果不考虑额外的空间的话,我们只需要把链表中的数字存储到数组中然后判断即可。
如果不用额外空间的话,我们可以把链表分成两半,把后一半倒置,和前一半依次判断即可。
解法一
两个关键点。
链表分成两半。
最直接的方法就是先遍历一遍链表得到链表的长度
n,然后再遍历n/2次就找到了中点。还有一个比较 trick 的方法,在 143 题,148 题 都用过了,也就是快慢指针,快指针一次走两步,慢指针一次走一步,当快指针走到终点的时候,慢指针此时就到了中点。
// 找中点,链表分成两个 ListNode slow = head; ListNode fast = head; while (fast != null && fast.next != null) { slow = slow.next; fast = fast.next.next; }需要注意的是,当链表个数为偶数的时候,
slow指向第二个链表的开始。当链表个数为奇数的时候是,slow指向最中间的位置。链表倒置
在 第 2 题 的时候已经介绍过链表倒置了。
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; }
然后整体的代码就出来了。
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;
}
总
其实还有一个争议的地方,利用输入的数据,算不算空间复杂度是 O(1),上边的解法我们改变了原来链表的结构,即使我们在 return 前可以再将链表还原,但如果较真的话,还是可以说它空间复杂度不是 O(1),因为如果输入的数据只是可读的,我们的算法确实需要额外空间。
详见 discuss-space") 里大神们的讨论,我觉得不用纠结,因为这完全取决于定义,定义的话不也是人定的吗,达成共识即可,具体问题再具体分析。