Leetcode 234. 回文链表

232 阅读2分钟

原题链接: 234. 回文链表 - 力扣(Leetcode)

tag: 双指针, 链表.

在阅读本文前, 请先阅读如下两篇题解.

Leetcode 876. 链表的中间结点 - 掘金 (juejin.cn)

Leetcode 206. 反转链表 - 掘金 (juejin.cn)

一. 题目

给你一个单链表的头节点 head , 请你判断该链表是否为回文链表. 如果是, 返回 true ; 否则, 返回 false .

二. 题解

本题需要复用两个之前做过的题目的函数, middleNodereverseList.

image.png

具体步骤如下.

1. 找到链表的中间节点

ListNode* mid = middleNode(head);

image.png

2. 从中间节点开始, 对链表后半段逆置

ListNode* rhead = reverseList(mid);

image.png

3. 开始比较链表的前半段和后半段

head != nullptr && rhead != nullptr

image.png

head->val == rhead->val

继续比较链表前半段和后半段.

image.png

更新 head 指针.

head = head->next;

image.png

更新 rhead 指针.

rhead = rhead->next;

image.png

继续比较链表前半段和后半段.

head != nullptr && rhead != nullptr

image.png

head->val == rhead->val

image.png

更新 head 指针.

head = head->next;

image.png

更新 rhead 指针.

rhead = rhead->next;

image.png

rhead 遍历链表后半段结束, while 循环终止.

image.png

return true;

image.png

三. 复杂度分析

时间复杂度: O(N), N 是链表的长度.

空间复杂度: O(1).

四. 代码

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode() : val(0), next(nullptr) {}
 *     ListNode(int x) : val(x), next(nullptr) {}
 *     ListNode(int x, ListNode *next) : val(x), next(next) {}
 * };
 */
class Solution {
public:
    ListNode* middleNode(ListNode* head) {
        ListNode* slow = head, * fast = head;    // 定义慢指针 slow, 快指针 fast
        while (fast && fast->next) {
            slow = slow->next;    // 慢指针走一步
            fast = fast->next->next;    // 快指针走两步
        }
        return slow;    // 返回链表的中间节点
    }

    ListNode* reverseList(ListNode* head) {
        ListNode* prev = nullptr, * curr = head;    // 定义前指针 prev, 中指针 curr
        while (curr != nullptr) {
            ListNode* temp = curr->next;    // 保存 curr 的后继节点
            curr->next = prev;    // 进行反转操作
            prev = curr;    // 更新 prev 指针
            curr = temp;    // 更新 curr 指针
        }
        return prev;    // 返回新的头节点
    }
    
    bool isPalindrome(ListNode* head) {
        ListNode* mid = middleNode(head);    // 找到链表的中间节点
        ListNode* rhead = reverseList(mid);    // 反转链表的后半部分
        
        while (head && rhead) {    // 比较链表的前半段和后半段
            if (head->val != rhead->val) {
                return false;
            }
            
            head = head->next;    // 更新 head 指针
            rhead = rhead->next;    // 更新 rhead 指针
        }
        return true;
    }
};