题目来源
160. 相交链表
面试题 02.07. 链表相交
剑指 Offer 52. 两个链表的第一个公共节点
题目描述

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 *getIntersectionNode(ListNode *headA, ListNode *headB) {
}
};
题目解析
如果两个单链表有共同的节点,那么从第一个共同节点开始,后面的节点都会重叠,直到链表结束。
因为两个链表中有一个共同节点,则这个节点里的指针域指向的下一个节点地址一样,所以下一个节点也会相交,依次类推。所以,若相交,则两个链表呈“Y”字形。如下图:
遍历记录链表长度

class Solution {
public:
ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
if (headA == nullptr || headB == nullptr){ // 只要有一个是空链表,就一定不会相交
return nullptr;
}
ListNode *tempA = headA;
int a1 = 1;
while (tempA->next != nullptr){
a1++;
tempA = tempA->next;
}
ListNode *tempB = headB;
int a2 = 1;
while (tempB->next != nullptr){
a2++;
tempB = tempB->next;
}
if(tempB != tempB){
return nullptr;
}
int diff = std::abs(a1 - a2);
if (a1 >= a2){
tempA = headA;
tempB = headB;
}
if (a2 > a1){
tempA = headB;
tempB = headA;
}
for (int i = 0; tempA != nullptr && i < diff; i++){
tempA = tempA->next;
}
while (tempA != nullptr && tempB != nullptr && tempA != tempB){
tempA = tempA->next;
tempB = tempB->next;
}
return tempA;
}
};
使用栈
从头遍历两个链表。创建两个栈,第一个栈存储第一个链表的节点,第二个栈存储第二个链表的节点。每遍历一个节点时,就将该节点入栈。
两个链表都入栈结束之后,则通过top判断栈顶的节点是否相等,如果相等则两个链表相交:如果两个链表相交,则从第一个相交节点开始,后面的节点都相交。
如果两链表相交,则循环出栈,直到遇到两个出栈的节点不相同,则这个节点的后一个节点就是第一个相交的节点。
栈问题要:小心栈溢出
class Solution {
public:
ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
std::stack<ListNode *> stackA , stackB;
ListNode *temp;
temp = headA;
while (temp){
stackA.push(temp);
temp = temp->next;
}
temp = headB;
while (temp){
stackB.push(temp);
temp = temp->next;
}
while (!stackA.empty() && !stackB.empty() && stackA.top() == stackB.top()){
temp = stackA.top();
stackA.pop();
stackB.pop();
}
return temp;
}
};
使用set
还可以使用hash
遍历链表A,将A中节点对应的指针(地址)插入set中;
遍历链表B,将B中节点对应的指针(地址)在set中查找,发现在set中的第一个节点地址,即为两个链表的交点。
class Solution {
public:
ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
if(headA == nullptr || headB == nullptr){
return nullptr;
}
std::unordered_set<ListNode *> set;
ListNode *temp = headA;
while (temp != nullptr){
set.insert(temp);
temp = temp->next;
}
temp = headB;
while (temp){
if(set.count(temp)){
return temp;
}
temp = temp->next;
}
return nullptr;
}
};
双指针(最优解)
思路是双指针,分别指向两个链表的头节点,循环这个链表,之后再去循环另一个链表。
分为两种情况:
一种是没有交点;
循环之后就返回 NULL,因为没有交点。
另一种是有交点;
原理:
AD + DC + BD = BD + DC + AD
class Solution {
public:
ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
if(headA == nullptr || headB == nullptr){
return nullptr;
}
ListNode * currA = headA;
ListNode * currB = headB;
while (currA != currB){
currA = (currA == NULL) ? headB : currA->next;
currB = (currB == NULL) ? headA : currB->next;
}
return currA;
}
};
类似题目
| 题目 | |
|---|---|
| leetcode:599. 两个列表的最小索引总和 Minimum Index Sum of Two Lists | |
| leetcode:160. 相交链表 Intersection of Two Linked Lists |