剑指Offer----面试题37:两个链表的第一个公共结点

题目:


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

方法一:


在第一个链表上顺序遍历每个每个结点,每遍历到一个结点的时候,再第二个链表上顺序遍历每个结点。如果第二个链表上有一个结点和第一个链表上的结点一样,说明两个链表在这个结点上重合,于是就找到了他们的公共结点。

如果第一个链表的长度为O(m),第二个链表的长度为O(n),显然该方法的时间复杂度为O(mn)。

代码如下:
/*
	输入两个链表,找出他们的第一个公共结点。
*/

#include<iostream>
#include"List.h"

using namespace std;
using namespace ListSpace5;

ListNode *FindFirstPulicNode(ListNode *root1, ListNode *root2)
{
	if (root1 == nullptr || root2 == nullptr)
		return nullptr;

	while (root1 != nullptr)
	{
		int  value = root1->element;
		ListNode *tempRoot2 = root2;
		while (tempRoot2 != nullptr)
		{
			if (tempRoot2->element == value && tempRoot2 == root1)
				return tempRoot2;

			tempRoot2 = tempRoot2->next;
		}
		root1 = root1->next;
	}

	return nullptr;
}

void test1()
{
	ListNode *list1 = CreateListNode(1);
	ListNode *list2 = CreateListNode(2);
	ListNode *list3 = CreateListNode(3);
	ListNode *list4 = CreateListNode(4);
	ListNode *list5 = CreateListNode(5);
	ListNode *list6 = CreateListNode(6);
	ListNode *list7 = CreateListNode(7);

	ConnectListNodes(list1, list2);
	ConnectListNodes(list2, list3);
	ConnectListNodes(list3, list6);
	ConnectListNodes(list6, list7);
	ConnectListNodes(list7, nullptr);

	ConnectListNodes(list4, list5);
	ConnectListNodes(list5, list6);
	
	cout << "第一个链表:" << endl;
	printList(list1);
	cout << endl;
	cout << "第二个链表:" << endl;
	printList(list4);
	cout << endl;

	ListNode *result = FindFirstPulicNode(list1, list4);
	if (result == nullptr)
		cout << "两个链表无公共结点" << endl;
	else
	{
		cout << "两个链表存在公共结点:";
		printListNode(result);
	}
	cout << endl;
}

int main()
{
	test1();
	cout << endl;

	system("pause");
	return 0;
}

运行结果:
第一个链表:
1  2  3  6  7
第二个链表:
4  5  6  7
两个链表存在公共结点:The value of this node is 6


请按任意键继续. . .

方法二:


使用两个栈分别存储两个链表的各个结点,这样两个链表的尾结点就位于两个栈的栈顶,接下来比较两个栈顶的结点是否相同,如果相同,则把栈顶弹出接着比较下一个栈顶,直到找到一个相同的结点。

在上述思路中,需要借助两个辅助的栈,如果两个链表的长度分别为m和n,那么空间复杂度是O(m+n),时间复杂度是O(m+n)。

代码如下:
#include<iostream>
#include<stack>
#include"List.h"

using namespace std;
using namespace ListSpace5;

ListNode *FindFirstPulicNode2(ListNode *root1, ListNode *root2)
{
	if (root1 == nullptr || root2 == nullptr)
		return nullptr;

	stack<ListNode *> stk1;
	stack<ListNode *> stk2;

	ListNode *temp1 = root1;
	ListNode *temp2 = root2;

	while (temp1 != nullptr)
	{
		stk1.push(temp1);
		temp1 = temp1->next;
	}

	while (temp2 != nullptr)
	{
		stk2.push(temp2);
		temp2 = temp2->next;
	}

	//如果最后一个结点都不同的话,直接返回nullptr
	if (stk1.top() != stk2.top())
		return nullptr;

	ListNode *node = nullptr;
	while (!stk1.empty() && !stk2.empty())
	{
		if (stk1.top() == stk2.top())
		{
			node = stk1.top();
			stk1.pop();
			stk2.pop();
		}
		else
			return node;
	}

	return nullptr;
}

void test21()
{
	ListNode *list1 = CreateListNode(1);
	ListNode *list2 = CreateListNode(2);
	ListNode *list3 = CreateListNode(3);
	ListNode *list4 = CreateListNode(4);
	ListNode *list5 = CreateListNode(5);
	ListNode *list6 = CreateListNode(6);
	ListNode *list7 = CreateListNode(7);

	ConnectListNodes(list1, list2);
	ConnectListNodes(list2, list3);
	ConnectListNodes(list3, list6);
	ConnectListNodes(list6, list7);
	ConnectListNodes(list7, nullptr);

	ConnectListNodes(list4, list5);
	ConnectListNodes(list5, list6);

	cout << "第一个链表:" << endl;
	printList(list1);
	cout << endl;
	cout << "第二个链表:" << endl;
	printList(list4);
	cout << endl;

	ListNode *result = FindFirstPulicNode2(list1, list4);
	if (result == nullptr)
		cout << "两个链表无公共结点" << endl;
	else
	{
		cout << "两个链表存在公共结点:";
		printListNode(result);
	}
	cout << endl;
}

int main()
{
	test21();
	cout << endl;

	system("pause");
	return 0;
}

运行结果:
第一个链表:
1  2  3  6  7
第二个链表:
4  5  6  7
两个链表存在公共结点:The value of this node is 6


请按任意键继续. . .

方法三


首先遍历两个链表得到他们的长度,这时候就知道哪个链表长以及长链表比锻炼表多出多少个结点。在第二次遍历的时候,先让较长的链表走上若干步,接着在同时在两个链表上遍历,找到第一个相同的结点就是他们的第一个公共结点。

时间复杂度为O(m+n),且不需要辅助空间。

代码如下:
#include<iostream>
#include"List.h"

using namespace std;
using namespace ListSpace5;

int GetListLength(ListNode *root)
{
	int length = 0;
	ListNode *temp = root;
	while (temp != nullptr)
	{
		++length;
		temp = temp->next;
	}

	return length;
}

ListNode *FindFirstPulicNode3(ListNode *root1, ListNode *root2)
{
	if (root1 == nullptr || root2 == nullptr)
		return nullptr;

	int len1 = GetListLength(root1);
	int len2 = GetListLength(root2);
	int step = len1 - len2;
	ListNode *nodeLong = root1;
	ListNode *nodeShort = root2;

	if (len2 > len1)
	{
		nodeLong = root2;
		nodeShort = root1;
		step = len2 - len1;
	}

	for (int i = 0; i < step; ++i)
		nodeLong = nodeLong->next;

	while (nodeLong != nullptr && nodeShort != nullptr)
	{
		if (nodeLong == nodeShort)
			return nodeLong;
		else
		{
			nodeLong = nodeLong->next;
			nodeShort = nodeShort->next;
		}
	}
	
	return nullptr;
}

void test31()
{
	ListNode *list1 = CreateListNode(1);
	ListNode *list2 = CreateListNode(2);
	ListNode *list3 = CreateListNode(3);
	ListNode *list4 = CreateListNode(4);
	ListNode *list5 = CreateListNode(5);
	ListNode *list6 = CreateListNode(8);
	ListNode *list7 = CreateListNode(7);

	ConnectListNodes(list1, list2);
	ConnectListNodes(list2, list3);
	ConnectListNodes(list3, list6);
	ConnectListNodes(list6, list7);
	ConnectListNodes(list7, nullptr);

	ConnectListNodes(list4, list5);
	ConnectListNodes(list5, list6);

	cout << "第一个链表:" << endl;
	printList(list1);
	cout << endl;
	cout << "第二个链表:" << endl;
	printList(list4);
	cout << endl;

	ListNode *result = FindFirstPulicNode3(list1, list4);
	if (result == nullptr)
		cout << "两个链表无公共结点" << endl;
	else
	{
		cout << "两个链表存在公共结点:";
		printListNode(result);
	}
	cout << endl;
}

int main()
{
	test31();
	cout << endl;

	system("pause");
	return 0;
}

运行结果:
第一个链表:
1  2  3  8  7
第二个链表:
4  5  8  7
两个链表存在公共结点:The value of this node is 8


请按任意键继续. . .




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值