C++寻找两个链表的交点

本文详细介绍了一种高效的链表交点查找算法,包括在有环和无环情况下的处理方法。通过使用快慢指针策略,算法能够精确地定位链表的环入口和计算链表长度。对于两个链表,无论它们是否有环,该算法都能找到第一个交点,适用于多种应用场景。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

算法思想

链表明确无环下 findIntersectWithoutRing

这种情况,只需要使用两个指针进行一次遍历就可以了。
注:可以假想成两个链表彼此相连,即list2连到list1后面,list1连在list2后面;

链表可能有环 findIntersect

首先需要判断两个链表是否有环,环的入口,以及不重复节点的数量;

  1. 当两个链表其中一个无环,另一个有环时,必然没有交点;
  2. 当两个链表都有环,且环的入口不一致时,需要判断是否为同一个环;如果是同一个环,则返回其中一个环入口,否则,必然没有交点;
  3. 其它情况下(即链表无环,或者环的入口一致),将长链表先前进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;
}
你好,下面是用C++创建两个相交链表的示例代码: ```c++ #include <iostream> using namespace std; // 定义链表节点 struct ListNode { int val; ListNode *next; ListNode(int x) : val(x), next(NULL) {} }; // 创建两个相交链表 ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) { ListNode *p1 = headA, *p2 = headB; while (p1 != p2) { // 遍历到链表末尾后,从另外一个链表头部继续遍历 p1 = p1 == nullptr ? headB : p1->next; p2 = p2 == nullptr ? headA : p2->next; } return p1; } int main() { // 创建第一个链表 ListNode *headA = new ListNode(1); ListNode *n1 = new ListNode(2); ListNode *n2 = new ListNode(3); ListNode *n3 = new ListNode(4); headA->next = n1; n1->next = n2; n2->next = n3; // 创建第二个链表 ListNode *headB = new ListNode(5); ListNode *m1 = new ListNode(6); ListNode *m2 = new ListNode(7); ListNode *m3 = n2; // 第二个链表从第一个链表的第三个节点开始相交 headB->next = m1; m1->next = m2; m2->next = m3; // 遍历两个链表验证相交 ListNode *intersectionNode = getIntersectionNode(headA, headB); if (intersectionNode != nullptr) { cout << "链表交点为:" << intersectionNode->val << endl; } else { cout << "链表不相交" << endl; } return 0; } ``` 输出结果: ``` 链表交点为:3 ``` 在这个例子中,我们创建了两个相交链表,然后通过 `getIntersectionNode` 函数遍历两个链表到它们的相交点,并返回相交点的指针。在主函数中,我们输出了相交点的值。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值