牛客:链表的回文结构详解

链表的回文结构_牛客题霸_牛客网

cpp 复制代码
/*
struct ListNode {
    int val;
    struct ListNode *next;
    ListNode(int x) : val(x), next(NULL) {}
};*/
#include <cstddef>

// 反转链表函数:将链表反转并返回新的头节点
struct ListNode* reverseList(struct ListNode* head){
    struct ListNode *newhead = NULL;  // 新链表的头节点(初始为空)
    struct ListNode *cur = head;      // 当前处理的节点
    
    // 遍历原链表,逐个节点反转
    while(cur) {
        struct ListNode *next = cur->next;  // 保存下一个节点的指针
        
        // 将当前节点连接到新链表的头部
        cur->next = newhead;
        newhead = cur;  // 更新新链表的头节点为当前节点
        
        cur = next;  // 处理下一个节点
    }
    return newhead;  // 返回后的链表头节点
}

class PalindromeList {
public:
    bool chkPalindrome(ListNode* A) {
        // 思路:通过快慢指针针找到链表中点,反转后半部分,再与前半部分比较
        
        // 特殊情况处理:空链表或单节点链表都是回文
        if(A == NULL || A->next == NULL) return true;
        
        ListNode *fast = A;  // 快指针(一次走两步)
        ListNode *slow = A;  // 慢指针(一次走一步)
        ListNode *prev = NULL;  // 用于记录慢指针的前一个节点
        
        // 1. 找到链表的中点
        // 当快指针到达尾部时,慢指针刚好在中点位置
        while(fast && fast->next) {
            prev = slow;          // 保存慢指针当前位置
            slow = slow->next;    // 慢指针前进一步
            fast = fast->next->next;  // 快指针前进两步
        }
        
        // 2. 将前半部分链表的尾部断开(与后半部分分离)
        prev->next = NULL;
        
        // 3. 反转后半部分链表
        slow = reverseList(slow);
        
        // 4. 比较前半部分和反转后的后半部分
        while(A) {  // 前半部分遍历完即结束
            // 若对应节点值不相等,则不是回文
            if(A->val != slow->val)
                return false;
            else {
                A = A->next;    // 前半部分后移
                slow = slow->next;  // 后半部分后移
            }
        }
        
        // 所有对应节点值都相等,是回文
        return true;
    }
};

/* 样例讲解:
假设链表为:1 -> 2 -> 3 -> 2 -> 1(是回文)

步骤1:找中点
- 初始:fast=1, slow=1, prev=NULL
- 第一次循环:prev=1, slow=2, fast=3
- 第二次循环:prev=2, slow=3, fast=1(fast->next为NULL,退出循环)
此时slow指向中点3,prev指向2

步骤2:断开前半部分
prev->next=NULL → 前半部分变为:1->2

步骤3:反转后半部分
原后半部分:3->2->1 → 反转后:1->2->3

步骤4:比较两部分
- A=1, slow=1 → 相等
- A=2, slow=2 → 相等
- A=NULL(前半部分结束)→ 循环退出

返回true,判断为回文


另一个样例:1->2->3->4(不是回文)
步骤1:找中点后,前半部分1->2,后半部分3->4
步骤2:反转后半部分为4->3
步骤3:比较1 vs 4 → 不相等,返回false
*/