原题链接: 234. 回文链表 - 力扣(Leetcode)
tag: 双指针, 链表.
在阅读本文前, 请先阅读如下两篇题解.
Leetcode 876. 链表的中间结点 - 掘金 (juejin.cn)
Leetcode 206. 反转链表 - 掘金 (juejin.cn)
一. 题目
给你一个单链表的头节点 head
, 请你判断该链表是否为回文链表. 如果是, 返回 true
; 否则, 返回 false
.
二. 题解
本题需要复用两个之前做过的题目的函数, middleNode
和 reverseList
.
具体步骤如下.
1. 找到链表的中间节点
ListNode* mid = middleNode(head);
2. 从中间节点开始, 对链表后半段逆置
ListNode* rhead = reverseList(mid);
3. 开始比较链表的前半段和后半段
head != nullptr && rhead != nullptr
head->val == rhead->val
继续比较链表前半段和后半段.
更新 head
指针.
head = head->next;
更新 rhead
指针.
rhead = rhead->next;
继续比较链表前半段和后半段.
head != nullptr && rhead != nullptr
head->val == rhead->val
更新 head
指针.
head = head->next;
更新 rhead
指针.
rhead = rhead->next;
rhead
遍历链表后半段结束, while
循环终止.
return true;
三. 复杂度分析
时间复杂度: 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;
}
};