链表的回文结构
题目如下图所示:

思路1:数组辅助法
此题也可以先把链表中的元素值全部保存到数组中,然后再判断数组是否为回文。不建议使用这种解法,因为如果没有告诉链表最大长度,则不能同此解法
cpp
class PalindromeList {
public:
bool chkPalindrome(ListNode* A) {
// write code here
int a[900] = {0};
ListNode* cur = A;
int n = 0;
//保存链表元素
while(cur)
{
a[n++] = cur->val;
cur = cur->next;
}
//判断数组是否为回文结构
int begin = 0, end = n-1;
while(begin < end)
{
if(a[begin] != a[end])
return false;
++begin;
--end;
}
return true;
}
};
思路2:快慢指针+反转
首先定位链表的中点,然后将后半部分进行反转操作,最后将前后两段进行逐一比对
cpp
#include <cstddef>
class PalindromeList {
public:
bool chkPalindrome(ListNode* A) {
if(A == NULL || A->next == NULL)
return true;
//找中间节点
// 使用快慢指针找中间节点
ListNode* slow = A;
ListNode* fast = A;
while (fast->next && fast->next->next) {
slow = slow->next;
fast = fast->next->next;
}
//对后续节点进行逆置(也可以称作翻转指针的指向),从中间节点的下一个节点开始逆置
ListNode* phead = NULL;//保存前一个指针的节点
ListNode* pnext = slow->next;//保存下一个指针的节点
ListNode* cur = pnext->next;
while(pnext)
{
if(cur == NULL)
{
pnext->next = phead;
break;
}
pnext->next = phead;
phead = pnext;
pnext = cur;
cur = cur->next;
}
ListNode* pcur = pnext;
while(pcur != NULL)
{
if(A->val != pcur->val)
{
return false;
}
A = A->next;
pcur = pcur->next;
}
return true;
}
};
也有一种更简洁的写法:
cpp
class PalindromeList {
public:
bool chkPalindrome(ListNode* A) {
if (A == NULL || A->next == NULL)
return true;
ListNode* slow, *fast, *prev, *cur, *nxt;
slow = fast = A;
//找到中间节点
while (fast && fast->next)
{
slow = slow->next;
fast = fast->next->next;
}
prev = NULL;
//后半部分逆置
cur = slow;
while (cur)
{
nxt = cur->next;
cur->next = prev;
prev = cur;
cur = nxt;
}
//逐点比对
while (A && prev)
{
if (A->val != prev->val)
return false;
A = A->next;
prev = prev->next;
}
return true;
}
};
相交链表
题目如下图所示:

思路1:双指针法
判断尾指针是否相交,相交找出第一个交点(地址判断)
时间复杂度O(n)
cpp
struct ListNode *getIntersectionNode(struct ListNode *headA, struct ListNode *headB) {
int len1 = 0;
int len2 = 0;
struct ListNode *cur1 = headA;
struct ListNode *cur2 = headB;
while(cur1)
{
len1++;
cur1 = cur1->next;
}
while(cur2)
{
len2++;
cur2 = cur2->next;
}
int gap = abs(len1 - len2);//abs在c语言中是求绝对值的
//目的:不用分具体是哪个链表较长了
struct ListNode *longlist = headA;
struct ListNode *shortlist = headB;
if(len1 < len2)
{
longlist = headB;
shortlist = headA;
}
while(gap)
{
longlist = longlist->next;
gap--;
}
while(longlist && shortlist)
{
if(longlist == shortlist)
{
return longlist;
}
longlist = longlist->next;
shortlist = shortlist->next;
}
return NULL;
}
思路2:暴力解法
A链表的节点依次跟B链表所有节点比较,A链的某个节点跟B链的某个节点相等,这个节点就是交点(不可以同时比较)
时间复杂度O(n*n)
cpp
struct ListNode *p1 = headA;
struct ListNode *p2 = headB;
while(p1)
{
p2 = headB;//一定要记得这个步骤,否则容易导致p2为空,第二次循环及以后比较的结果都不正确
while(p2)
{
if(p1 == p2)
{
return p1;
}
p2 = p2->next;
}
p1 = p1->next;
}
return NULL;
总结
本文通过 相交链表 和 链表的回文结构 两道经典题目,深入分析了链表操作中的不同解法效率:
相交链表解法对比
| 思路 | 方法 | 时间复杂度 | 空间复杂度 | 优缺点 |
|---|---|---|---|---|
| 思路1 | 暴力解法 | O(m×n) | O(1) | 简单但效率低 |
| 思路2 | 双指针法 | O(m+n) | O(1) | 最优解,推荐使用 |
链表的回文结构解法对比
| 思路 | 方法 | 时间复杂度 | 空间复杂度 | 优缺点 |
|---|---|---|---|---|
| 思路1 | 数组辅助法 | O(n) | O(n) | 直观易懂 |
| 思路2 | 快慢指针+反转 | O(n) | O(1) | 最优解 |
✅ 核心收获
-
双指针法解决相交链表:通过路径拼接,优雅地找到交点
-
快慢指针+反转解决回文:原地操作,空间O(1)
-
边界处理:链表为空的处理、奇偶长度的处理
-
面试技巧:先给出直观解法,再逐步优化到最优解
📌 下期预告
下一期我们将继续 【数据结构系列04】 ,进入链表进阶专题(二),一起来看看三道经典题目:
【复制带随机指针的链表】:如何深度拷贝一个带有随机指针的复杂链表?
【判断链表中是否有环】:如何检测链表中是否存在环?
【环形链表 II】:如果链表有环,如何找到环的入口节点?
如果你对链表操作还有疑问,欢迎在评论区留言讨论!如果觉得有帮助,别忘了点赞、收藏、关注,我们下期见!
