160. Intersection of Two Linked Lists

1.题目

Write a program to find the node at which the intersection of two singly linked lists begins.

For example, the following two linked lists:
在这里插入图片描述

begin to intersect at node c1.

Example 1:
在这里插入图片描述

Input: intersectVal = 8, listA = [4,1,8,4,5], listB = [5,0,1,8,4,5], skipA = 2, skipB = 3
Output: Reference of the node with value = 8
Input Explanation: The intersected node’s value is 8 (note that this must not be 0 if the two lists intersect). From the head of A, it reads as [4,1,8,4,5]. From the head of B, it reads as [5,0,1,8,4,5]. There are 2 nodes before the intersected node in A; There are 3 nodes before the intersected node in B.

Example 2:
在这里插入图片描述

Input: intersectVal = 2, listA = [0,9,1,2,4], listB = [3,2,4], skipA = 3, skipB = 1
Output: Reference of the node with value = 2
Input Explanation: The intersected node’s value is 2 (note that this must not be 0 if the two lists intersect). From the head of A, it reads as [0,9,1,2,4]. From the head of B, it reads as [3,2,4]. There are 3 nodes before the intersected node in A; There are 1 node before the intersected node in B.

Example 3:
在这里插入图片描述

Input: intersectVal = 0, listA = [2,6,4], listB = [1,5], skipA = 3, skipB = 2
Output: null
Input Explanation: From the head of A, it reads as [2,6,4]. From the head of B, it reads as [1,5]. Since the two lists do not intersect, intersectVal must be 0, while skipA and skipB can be arbitrary values.
Explanation: The two lists do not intersect, so return null.

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.

2.C++代码

方法1:BruteForce
对于A链表的每个节点,遍历整个B链表,检测是否存在交叉的节点
代码如下:

ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) 
{
	if (headA == nullptr || headB == nullptr)
		return nullptr;
	if (headA == headB)
		return headA;
	ListNode*L1 = new ListNode(0); L1->next = headA;
	ListNode*L2 = new ListNode(0); L2->next = headB;
	while (L1->next)
	{
		ListNode*p = L2;
		while (p->next)
		{
			if (p->next == L1->next)
				return p->next;
			p = p->next;
		}
		L1=L1->next;
	}
	return nullptr;
}

复杂度分析:
时间复杂度:O(mn)
空间复杂度:O(1)

方法2:双指针方法
两个指针中L1指向headA,L2指向headB,他们同时后移,直到他们到达链尾,这是指针指向另一个链表头部(比如,L1到达尾部,则指向headB,L2到达尾部,则指向headA),经过一次交换链表的指向后,可以开始判断是否有共同的交叉节点了

ListNode *getIntersectionNode3(ListNode *headA, ListNode *headB)
{
	if (headA == nullptr || headB == nullptr)
		return nullptr;
	if (headA == headB)
		return headA;
	ListNode*L1 = headA;
	ListNode*L2 = headB;
	while (L1&&L2){L1 = L1->next;L2 = L2->next;}
	if (L1 == nullptr&&L2)
	{
		L1 = headB;
		while (L1)
		{
			if (L1 == L2) return L1;
			L1 = L1->next; L2 = L2->next;
			if (L2 == nullptr)L2 = headA;
		}
	}
	else if(L2== nullptr&&L1)
	{
		L2 = headA;
		while (L2)
		{
			if (L1 == L2)return L1;
			L1 = L1->next; L2 = L2->next;
			if (L1 == nullptr)L1 = headB;
		}
	}
	else
	{
		L1 = headA;
		L2 = headB;
		while (L1)
		{
			if (L1 == L2) return L1;
			L1 = L1->next; L2 = L2->next;
		}
	}
	return nullptr;
}

上面的代码比较繁琐,含有较多的重复代码,进行优化如下:

//beats 64%
ListNode *getIntersectionNode4(ListNode *headA, ListNode *headB)
{
	if (headA == nullptr || headB == nullptr)
		return nullptr;
	if (headA == headB)
		return headA;
	ListNode*L1 = headA;ListNode*L2 = headB;
	bool flag = 0;
	while (L1&&L2)
	{
		if (L1 == L2)return L1;
		L1 = L1->next;
		L2 = L2->next;
		if (flag == 0)
		{
			if ((L1 == nullptr)&&(L2 == nullptr)) break;
			else if (L1 == nullptr) { L1 = headB; flag == 1; }
			else { L2 = headA; flag == 1; }
		}
	}
	return nullptr;
}

还可以简化:
性能并没有提升;

//beats 38%
ListNode *getIntersectionNode5(ListNode *headA, ListNode *headB)
{
	if (headA == nullptr || headB == nullptr)
		return nullptr;
	if (headA == headB)
		return headA;
	ListNode*L1 = headA; ListNode*L2 = headB;
	while (L1 != L2)
	{
		L1 = (L1 == nullptr) ? headB : L1->next;
		L2 = (L2 == nullptr) ? headA : L2->next;
	}
	return L1;
}

复杂度分析:
时间复杂度:O(m+n)
空间复杂度:O(1)

方法3:基于链表长度
其实是上面的方法2的变形,先遍历两个链表,获取两个链表的长度len1和len2,对较长的链表的指针进行后移
|len1-len2|,这样两个指针后面的链表长度一样了,开始同步后移遍历,检测交叉节点。
代码如下:

//beats 66%
ListNode *getIntersectionNode2(ListNode *headA, ListNode *headB)
{
	if (headA == nullptr || headB == nullptr)
		return nullptr;
	if (headA == headB)
		return headA;
	ListNode*L1 = new ListNode(0); L1->next = headA; headA = L1;
	ListNode*L2 = new ListNode(0); L2->next = headB; headB = L2;
	int len1 = 0; int len2 = 0;
	while (L1){len1++;L1 = L1->next;}
	while (L2){len2++;L2 = L2->next;}
	while (len1 > len2) { headA = headA->next; len1--; }
	while (len1 < len2) { headB = headB->next; len2--; }
	while ((headA->next) && (headB->next))
	{
		if (headA->next == headB->next)
			return headA->next;
		headA = headA->next;
		headB = headB->next;
	}
	return nullptr;
}

简化的版本:

//beats 65%
ListNode *getIntersectionNode6(ListNode *headA, ListNode *headB)
{
	if (headA == nullptr || headB == nullptr)
		return nullptr;
	if (headA == headB)
		return headA;
	ListNode*L1 = headA; ListNode*L2 = headB;
	int len1 = 0; int len2 = 0;
	while (L1) { len1++; L1 = L1->next; }
	while (L2) { len2++; L2 = L2->next; }
	while (len1 > len2) { headA = headA->next; len1--; }
	while (len1 < len2) { headB = headB->next; len2--; }
	while (headA!= headB)
	{
		headA = headA->next;
		headB = headB->next;
	}
	return headA;
}

复杂度分析:
时间复杂度:O(m+n)
空间复杂度:O(1)

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值