C++代码随想录刷题知识分享-----面试题链表相交
一、题目要求
题目:给定两条单链表 headA
、headB
,找出它们相交的起始节点(节点对象相同而非数值相等)。若无交点返回 null
。
限制:链表无环;函数返回后链表结构不能被破坏。
图示两个链表在节点 c1 开始相交:
题目数据 保证 整个链式结构中不存在环。
注意,函数返回结果后,链表必须 保持其原始结构 。
示例 1:
示例 2:
示例 3:
二、解法 1 —— “先求长度差 + 对齐再同步”(时间 O(m+n),空间 O(1))
1. 思路
- 先各自遍历一次求出长度
lenA
、lenB
。 - 计算差值
d = |lenA - lenB|
。 - 让较长链先走
d
步,剩余部分两链长度一致。 - 两指针同时前进,第一次相遇即交点;若最后都为
null
则无交点。
2. C++代码
/*** Definition for singly-linked list.* struct ListNode {* int val;* ListNode *next;* ListNode(int x) : val(x), next(NULL) {}* };*/
class Solution {
public:ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {ListNode* curA = headA;ListNode* curB = headB;int lenA = 0;int lenB = 0;int chazhi;while(curA){curA=curA->next;lenA++;}while(curB){curB=curB->next;lenB++;}chazhi = abs(lenA-lenB);curA = headA;curB = headB;if (lenA>lenB){for(int i =0;i<chazhi;i++){curA=curA->next;}while(curA){if(curA==curB){return curA;}curA=curA->next;curB=curB->next;}}else{for(int i =0;i<chazhi;i++){curB=curB->next;}while(curA){if(curA==curB){return curA;}curA=curA->next;curB=curB->next;}}return NULL;}
};
三、解法 2 —— “双指针互跳”(一次扫描更简洁)
1. 关键思想
- 指针
pA
从 A 链头走到尾后 跳到 B 链头; - 指针
pB
从 B 链头走到尾后 跳到 A 链头; - 若存在交点,它们在第
lenA + lenB - k
步会同时到达交点; - 若无交点,两指针最终同时成为
nullptr
,循环结束。
整体只走两条链各一遍,总步数
lenA + lenB
。
2. C++代码
class Solution {
public:ListNode* getIntersectionNode(ListNode* headA, ListNode* headB) {// 若有任何一条为空,必无交点if (!headA || !headB) return nullptr;ListNode* pA = headA; // 指针 AListNode* pB = headB; // 指针 B/* 只要不相等就一直走:* - pA 走完链 A 就跳到链 B 的头* - pB 走完链 B 就跳到链 A 的头* 最多 lenA+lenB 步,两指针必同时为交点或同时为 nullptr*/while (pA != pB) {pA = (pA ? pA->next : headB); // 三元运算避免空指针访问pB = (pB ? pB->next : headA);}return pA; // 返回交点或 nullptr}
};
四、两种解法对比
指标 | 解法 1:先算长度差 | 解法 2:双指针互跳 |
---|---|---|
时间复杂度 | O(m + n) | O(m + n) |
额外空间 | O(1) | O(1) |
代码行数 | 略长(需两次遍历 + 对齐) | 极简 |
直观难度 | ★★ | ★★★(第一次见需要理解“互跳”) |
常用场景 | 任何面试都能过 | 高频高赞写法,面试官更青睐 |
五、重要知识点
知识点 | 速记 |
---|---|
比较节点地址 | 交点要判断 指针是否相同 ,不能只比较 val |
虚拟头 vs 不需要 | 本题不必修改原链结构,通常不加 dummy;若要改链可加 dummy |
时间下界 | 至少 O(m+n) ,因为每节点都需被访问 |
空间下界 | 题面要求 O(1) ,因此不能用 set、vector 存节点 |
互跳原理 | 走完自己链就走对方链,总步数相等,长短差抵消 |
无交点情况 | 双指针最终一起到 nullptr ,返回 nullptr |
六、面试官常追问
-
带环链表场景如何处理?
先用 Floyd 判环:- 若两链一无环一有环 → 一定不相交;
- 若都无环:按本题思路;
- 若都同环:分“交点在环前”与“在环内”两种讨论。
-
能否用递归?
理论可行但会消耗O(m+n)
递归栈,不推荐。 -
如果链表非常长(百万级),但内存紧张,使用哪种算法?
互跳法依旧O(1)
空间,非常适合。