【刷题笔记】单链表的相交问题(C++版)

题目:

输入两个链表,找出它们的第一个公共结点。

解题思路:

分为有环链表相交与无环链表相交问题,一个有环一个无环的链表相交情况不存在。

1判断两个链表是否有环,有环返回入环节点,无环返回NULL;

2两个无环链表->noLoop判断是否相交
1)末节点不一致一定不相交
2)末节点一致,长链表先遍历差值个节点,后同步遍历,第一个相等节点即为目标节点
在这里插入图片描述

3两个有环链表->bothLoop判断是否相交
1)判断拓扑类型
在这里插入图片描述
2)针对不同拓扑分情况判别:
(a)入环节点一致,从入环节点之前为无环链表相交的判定;
(b)入环节点不一致,从loop1遍历发现loop2节点,则两个链表相交,返回loop1和loop2均可;
©入环节点不一致,从loop1节点遍历未发现loop2节点,则两个有环链表不相交。

代码实现

1、主函数

#include<iostream>
using namespace std;

struct ListNode {
	int val;
	struct ListNode *next;
	ListNode(int x) :
			val(x), next(NULL) {
	}
};

ListNode* FindFirstCommonNode(ListNode* pHead1, ListNode* pHead2) {
	if (pHead1 == NULL || pHead2 == NULL)
	{
		return NULL;
	}
	ListNode* loop1 = getLoopNode(pHead1);
	ListNode* loop2 = getLoopNode(pHead2);//找到入环节点
	if (loop1 == NULL && loop2 == NULL)
	{
		return noLoop(pHead1, pHead2);
	}
	if (loop1 != NULL && loop2 != NULL)
	{
		return bothLoop(pHead1, loop1, pHead2, loop2);
	}
	return NULL;//一个有环一个无环不可能相交
}

2、获取入环节点函数

ListNode* getLoopNode(ListNode* pHead)
{
	if (pHead == NULL || pHead->next == NULL || pHead->next->next == NULL)
	{
		return NULL;//不构成环
	}
	ListNode* pSlow = pHead;
	ListNode* pFast = pHead->next->next;//快慢指针
	while (pSlow != pFast)//有环链表快指针必定在环上追上慢指针
	{
		if (pFast == NULL)
		{
			return NULL;//快指针走到空节点说明一定无环
		}
		pFast = pFast->next->next;
		pSlow = pSlow->next;
	}
	pFast = pHead;//追上后,快指针调至头结点,与慢指针同步前进,必定在如环节点相遇
	while (pSlow != pFast)
	{
		pSlow = pSlow->next;
		pFast = pFast->next;
	}
	return pSlow;
}

3、无环链表相交函数

ListNode* noLoop(ListNode* pHead1, ListNode* pHead2)
{
	if (pHead1 == NULL || pHead2 == NULL)
	{
		return NULL;
	}
	ListNode* p1 = pHead1;
	ListNode* p2 = pHead2;
	int n1 = 1;
	int n2 = 1;
	while (p1->next != NULL)
	{
		n1++;
		p1 = p1->next;
	}
	while (p2->next != NULL)
	{
		n2++;
		p2 = p2->next;
	}
	//p1和p2走到末节点
	if (p1 != p2)
	{
		return NULL;//末节点不相等则不相交
	}

	p1 = n1 > n2 ? pHead1 : pHead2;//p1为长链表
	p2 = p1 == pHead1 ? pHead2 : pHead1;//p2为短链表
	int n = n1 > n2 ? n1 - n2 : n2 - n1;//长度差值
	while (n != 0)
	{
		n--;
		p1 = p1->next;//长链表先走差值长度
	}
	while (p1 != p2)
	{
		p1 = p1->next;
		p2 = p2->next;//同步行进,相交点点处相遇
	}
	return p1;
}

4、有环链表相交函数

ListNode* bothLoop(ListNode* pHead1, ListNode* loop1, ListNode* pHead2, ListNode* loop2)
{
	ListNode* p1 = NULL;
	ListNode* p2 = NULL;
	if (loop1 == loop2)//结构(a),如环节点一致的相交有环链表
	{
		p1 = pHead1;
		p2 = pHead2;
		//以下类似于无环链表相交的判定
		int n1 = 1;
		int n2 = 1;
		while (p1 != loop1)//改为入环节点前的相交判定
		{
			n1++;
			p1 = p1->next;
		}
		while (p2 != loop2)
		{
			n2++;
			p2 = p2->next;
		}
		p1 = n1 > n2 ? pHead1 : pHead2;//p1为长链表
		p2 = p1 == pHead1 ? pHead2 : pHead1;//p2为短链表
		int n = n1 > n2 ? n1 - n2 : n2 - n1;//长度差值
		while (n != 0)
		{
			n--;
			p1 = p1->next;//长链表先走差值长度
		}
		while (p1 != p2)
		{
			p1 = p1->next;
			p2 = p2->next;//同步行进,相交点点处相遇
		}
		return p1;
	}
	else
	{
		p1 = loop1->next;
		while (p1 != loop1)
		{
			if (p1 == loop2)//在回到环起点前遇到loop2,(b)结构
			{
				return loop1;//默认返回loop1
			}
			p1 = p1->next;
		}
		return NULL;//结构(c)
	}
}

整理略有匆忙,如有问题欢迎指正共同探讨。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值