算法思想
链表明确无环下 findIntersectWithoutRing
这种情况,只需要使用两个指针进行一次遍历就可以了。
注:可以假想成两个链表彼此相连,即list2连到list1后面,list1连在list2后面;
链表可能有环 findIntersect
首先需要判断两个链表是否有环,环的入口,以及不重复节点的数量;
- 当两个链表其中一个无环,另一个有环时,必然没有交点;
- 当两个链表都有环,且环的入口不一致时,需要判断是否为同一个环;如果是同一个环,则返回其中一个环入口,否则,必然没有交点;
- 其它情况下(即链表无环,或者环的入口一致),将长链表先前进n步,使得两个链表剩下的长度相等,之后同时遍历一下,尝试找到第一个交点即可;
源代码
#pragma once
#include<vector>
using namespace std;
struct ListNode {
int val;
ListNode* next;
ListNode(int val):val(val),next(NULL){}
};
//发现环入口,以及链表长度
//快慢指针
pair<ListNode*,int> findRing(ListNode* list) {
int len = 0;
ListNode* fast = list;
ListNode* slow = list;
while (fast != NULL) {
slow = slow->next;
++len;
fast = fast->next;
if (fast != NULL)
fast=fast->next;
if (slow == fast)
break;
}
//无环情况下
if (fast == NULL) {
while (slow != NULL) {
slow = slow->next;
++len;
}
return pair<ListNode*, int>(NULL, len);
}
slow = list;
while (slow != fast) {
slow = slow->next;
fast = fast->next;
++len;
}
return pair<ListNode*, int>(slow, len);
}
//找到链表交点(可能有环)
ListNode* findIntersect(ListNode* list1, ListNode* list2) {
auto p1 = findRing(list1);
auto p2 = findRing(list2);
bool hasRing1 = p1.first != NULL;
bool hasRing2 = p2.first != NULL;
//其中一个有环,另一个无环,肯定没有交点;
if (hasRing1 ^ hasRing2)
return NULL;
//两个都有环,且入口不一致
if (hasRing1 && hasRing2&& p1.first != p2.first) {
ListNode* node = p1.first;
while (node!=p2.first) {
node = node->next;
if (node == p1.first) break;
}
//同一个环,返回其中一个入口
return node == p2.first ? node : NULL;
}
//两个都无环,或者两个都有环且环入口一致
ListNode* node1 = list1;
ListNode* node2 = list2;
int k= p1.second - p2.second;
//保证node1链表要长
if (k < 0) {
k = -k;
swap(node1, node2);
}
while (k-- > 0)
node1 = node1->next;
while (node1 != NULL && node2 != NULL && node1 != node2) {
node1 = node1->next;
node2 = node2->next;
}
return node1;
}
//找到链表是否相交(无环)
ListNode* findIntersectWithoutRing(ListNode* list1, ListNode* list2) {
ListNode* node1 = list1;
ListNode* node2 = list2;
while (node1 != node2) {
if (node1 == NULL) node1 = list2;
else node1 = node1->next;
if (node2 == NULL) node2 = list1;
else node2 = node2->next;
}
return node1;
}
测试代码
#include"ListIntersect.h"
#include<iostream>
#include<unordered_map>
using namespace std;
//创建链表
//需要保证输入合理
pair<ListNode*, ListNode*>create(const vector<int>& nums1, const vector<int>& nums2) {
ListNode tmp(-1);
unordered_map<int, ListNode*> hashMap;
ListNode* node = &tmp;
for (int i = 0; i < nums1.size(); ++i) {
ListNode* next = NULL;
if (hashMap.find(nums1[i]) != hashMap.end())
next = hashMap[nums1[i]];
else {
next = new ListNode(nums1[i]);
hashMap[nums1[i]] = next;
}
node->next = next;
node = node->next;
}
ListNode* list1 = tmp.next;
tmp.next = NULL;
node = &tmp;
for (int i = 0; i < nums2.size(); ++i) {
ListNode* next = NULL;
if (hashMap.find(nums2[i]) != hashMap.end())
next = hashMap[nums2[i]];
else {
next = new ListNode(nums2[i]);
hashMap[nums2[i]] = next;
}
node->next = next;
node = node->next;
}
ListNode* list2 = tmp.next;
return pair<ListNode*, ListNode*>(list1, list2);
}
int main() {
vector<int>nums1 = { 1,2,3,4,5,6,7,3};
vector<int>nums2 = { 9,6};
auto p= create(nums1, nums2);
auto node=findIntersect(p.first, p.second);
if (node == NULL)cout << "no" << endl;
else cout << node->val << endl;
}