Write a program to find the node at which the intersection of two singly linked lists begins.
For example, the following two linked lists:
A: a1 → a2
↘
c1 → c2 → c3
↗
B: b1 → b2 → b3
begin to intersect at node c1.
Notes:
- If the two linked lists have no intersection at all, return null.
- The linked lists must retain their original structure after the function returns.
- You may assume there are no cycles anywhere in the entire linked structure.
- Your code should preferably run in O(n) time and use only O(1) memory.
两条可能相交的链表找到交点,最简单的做法就是先遍历一个链表,将其中的节点放到集合中,然后再去遍历另一个链表,在遍历过程中与集合中的数据进行比较,如果集合中的节点与当前节点相等这说明这个节点是交点。
//先遍历一个链表,再遍历另一个链表
/*unordered_set<struct ListNode*> nodes;//用来存放
while(headA) {
nodes.insert(headA);
headA = headA->next;
}
while(headB) {
if(nodes.count(headB)) {
return headB;
}
headB = headB->next;
}
return NULL;*/
但是这个效率明显是最低的,可以稍微的优化一下,同时遍历两个链表并且放到集合中,每个链表都与集合中的数据进行比较。
//同时遍历两个链表
/*while(headA && headB) {
if(headA == headB) {
//cout << "0. " << headA->val;
return headA;
}
if(nodes.count(headA)) {//如果A节点在集合中能够找到,说明这是个交点
//cout << "1. " << headA->val;
return headA;
} else if(nodes.count(headB)) {//B
//cout << "2. " << headB->val;
return headB;
} else {
nodes.insert(headA);
nodes.insert(headB);
headA = headA->next;
headB = headB->next;
}
}
if(!headA) {//如果A遍历完了,需要遍历一下B,因为可能B比A的长度长,A的最后一个节点可能B的中间一个,而此时B还没有遍历到
while(headB) {
if(nodes.count(headB)) {
//cout << "4. " << headB->val;
return headB;
}
headB = headB->next;
}
}
if(!headB) {//同上
while(headA) {
if(nodes.count(headA)) {
//cout << "5. " << headA->val;
return headA;
}
headA = headA->next;
}
}
return NULL;*/
但是上述的效率都不是很高,有一种比较聪明的解法。因为如果两条链表如果有交叉的话,那么交叉遍历一下,必然会在交点的时候相遇。便利的时候使用两个指针从两个链表遍历,遍历完一条去遍历另一条。
比如官方给的例子中,用a指针指向上面的a1,用b指针指向下面的b1,那么a、b指针的过程如下:
a:a1、a2、c1、c2、c3、b1、b2、b3、c1。
b:b1、b2、b3、c1、c2、c3、a1、a2、c1。
可以看到因为两个指针交叉遍历了,所以如果有交点的话必然会相遇,如果两个链表交点前节点个数相等那么会在第一次遍历过程中就相遇了,如果长短不一的话将会在交叉之后的第二次遍历相遇。(这个第二次指的是a遍历完之后再去遍历b)
#include <iostream>
#include <unordered_set>
using namespace std;
struct ListNode {
int val;
ListNode *next;
ListNode(int x) : val(x), next(NULL) {}
};
class Solution {
public:
struct ListNode* getIntersectionNode(struct ListNode *headA, struct ListNode *headB) {
if(!headA || !headB) {
return NULL;
}
ListNode*a = headA;
ListNode*b = headB;
while(a!=b) {//相当于是交叉扫描一遍,如果有交点必然会相等
a = a == NULL ? headB : a->next;
b = b == NULL ? headA : b->next;
}
return a;
//先遍历一个链表,再遍历另一个链表
/*unordered_set<struct ListNode*> nodes;//用来存放
while(headA) {
nodes.insert(headA);
headA = headA->next;
}
while(headB) {
if(nodes.count(headB)) {
return headB;
}
headB = headB->next;
}
return NULL;*/
//同时遍历两个链表
/*while(headA && headB) {
if(headA == headB) {
//cout << "0. " << headA->val;
return headA;
}
if(nodes.count(headA)) {//如果A节点在集合中能够找到,说明这是个交点
//cout << "1. " << headA->val;
return headA;
} else if(nodes.count(headB)) {//B
//cout << "2. " << headB->val;
return headB;
} else {
nodes.insert(headA);
nodes.insert(headB);
headA = headA->next;
headB = headB->next;
}
}
if(!headA) {//如果A遍历完了,需要遍历一下B,因为可能B比A的长度长,A的最后一个节点可能B的中间一个,而此时B还没有遍历到
while(headB) {
if(nodes.count(headB)) {
//cout << "4. " << headB->val;
return headB;
}
headB = headB->next;
}
}
if(!headB) {
while(headA) {
if(nodes.count(headA)) {
//cout << "5. " << headA->val;
return headA;
}
headA = headA->next;
}
}
return NULL;*/
}
};
int main() {
Solution s;
ListNode node1(1);
ListNode node2(2);
ListNode node3(3);
ListNode node4(4);
ListNode node5(5);
ListNode node6(6);
node1.next = &node2;
node3.next = &node4;
node4.next = &node5;
node2.next = &node6;
node5.next = &node6;
ListNode * p = s.getIntersectionNode(&node1,&node3);
}