思路:

题目的主要信息:

  • 链表至少为1,不用担心为空
  • 判断单链表中的数值是否是回文

因为比较回文的基本思路是最前和最后比较,然后依次向中间靠齐,但是这是一个单链表,无法向前,所以我们要用另外的方法使它逆序。

方法一:中点逆链表法

具体做法:

找到链表长度,然后找到链表中间结点,从中间结点开始往后将链表指针反过来。然后比较前半部分和后半部分即可,因为后半部分相当于是逆序。 图片说明

class Solution {
public:
    ListNode* reverse(ListNode* head) { //反转链表指针
        ListNode* prev = NULL;
        while (head != NULL) {
            ListNode* next = head->next;
            head->next = prev;
            prev = head;
            head = next;
        }
    return prev;
}
    bool isPail(ListNode* head) {
        ListNode* p = head;
        int n = 0;
        while(p != NULL){ //找到链表长度
            n++;
            p = p->next; 
        }
        n = n / 2; //中点
        p = head;
        while(n > 0){
            p = p->next;
            n--;
        }
        p = reverse(p);  //中点处反转
        ListNode* q = head;
        while (p != NULL) {
            if (p->val != q->val) //比较判断节点值是否相等
                return false;
            p = p->next;
            q = q->next;
        }
        return true;
    }
};

复杂度分析:

  • 时间复杂度:O(n),找到链表长度、找到中点,两部分比较都是O(n)
  • 空间复杂度:O(1),没有额外空间

方法二:栈逆序法

具体做法:

因为需要逆序比较,因此可以首先遍历一次链表,并用栈来保存每个数值。 第二次遍历即可依次与出栈的数值比较,因为栈是先进后出,本身就是一个逆序。

class Solution {
public:
    bool isPail(ListNode* head) {
        ListNode* p = head;
        stack<int> s;
        while(p != NULL){
            s.push(p->val);
            p = p->next;
        }
        p = head;
        while(!s.empty()){
            if(p->val != s.top())
                return false;
            s.pop();
            p = p->next;
        }
        return true;
    }
};

复杂度分析:

  • 时间复杂度:O(n),两次遍历都是O(n)
  • 空间复杂度:O(n),使用了额外的栈空间