链表——回文链表
给你一个单链表的头节点 head ,请你判断该链表是否为回文链表。如果是,返回 true ;否则,返回 false 。
这道题要求判断一个但来年表是否是回文链表(正序和逆序完全一样),最优解法是:
快慢指针找中点+反转后半链表+前后同时遍历比较
时间复杂度** O(n),空间复杂度 O(1)**,不占用额外空间
解题思路
1.快慢指针找中点
- 快指针走两步,慢指针走一步
- 快指针到末尾时,慢指针正好在链表中点
2.反转后半链表
- 从中点开始,把后半段链表反转
3.前后两段逐一比较
- 前半段从头开始,后半段从反转后的新头开始
- 逐个节点对比,全部相等就是回文
完整代码实现如下:
#include
using namespace std;
// 链表节点定义
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:
bool isPalindrome(ListNode* head) {
if (head == nullptr || head->next == nullptr) {
return true; // 空链表或单个节点一定是回文
}
// 1. 快慢指针找中点
ListNode* slow = head;
ListNode* fast = head;
while (fast != nullptr && fast->next != nullptr) {
slow = slow->next;
fast = fast->next->next;
}
// 2. 反转后半段链表
ListNode* prev = nullptr;
ListNode* cur = slow;
while (cur != nullptr) {
ListNode* temp = cur->next;
cur->next = prev;
prev = cur;
cur = temp;
} // 循环结束后 prev 是后半段反转后的头节点
// 3. 前后两段逐一比较
ListNode* left = head;
ListNode* right = prev;
while (right != nullptr) {
if (left->val != right->val) {
return false;
}
left = left->next;
right = right->next;
}
return true; // 全部匹配
}
};
// 测试代码
int main() {
// 测试回文链表 1->2->2->1
ListNode* head1 = new ListNode(1);
head1->next = new ListNode(2);
head1->next->next = new ListNode(2);
head1->next->next->next = new ListNode(1);
// 测试非回文链表 1->2
ListNode* head2 = new ListNode(1);
head2->next = new ListNode(2);
Solution sol;
cout << boolalpha;
cout << "1->2->2->1: " << sol.isPalindrome(head1) << endl; // true
cout << "1->2: " << sol.isPalindrome(head2) << endl; // false
return 0;
}
代码逐段解释:
1.快慢指针找中点
ListNode* slow = head;
ListNode* fast = head;
while (fast != nullptr && fast->next != nullptr) {
slow = slow->next;
fast = fast->next->next;
}
- 快指针一次走两步,慢指针一次走一步
- 结束时,slow 指向链表中点(后半段起点)
2. 反转后半段链表(标准反转逻辑)
ListNode* prev = nullptr;
ListNode* cur = slow;
while (cur != nullptr) {
ListNode* temp = cur->next;
cur->next = prev;
prev = cur;
cur = temp;
}
- 反转后,prev 变成后半段新头
- 例如:2 -> 1 反转为 1 -> 2
3.前后两段逐一比较
ListNode* left = head;
ListNode* right = prev;
while (right != nullptr) {
if (left->val != right->val) return false;
left = left->next;
right = right->next;
}
- 从头和从反转后的头一起走
- 只要有一个值不相等 → 不是回文
- 全部相等 → 是回文
四、示例运行
原链表:1 → 2 → 2 → 1
1.找到中点:slow 指向第 2 个 2
2.反转后半段:1 → 2
3.对比:
left:1 → 2
right:1 → 2
全部相等 → 返回 true
浙公网安备 33010602011771号