160相交链表(双指针法)

1、题目描述

编写一个程序,找到两个单链表相交的起始节点。

注意:

  • 如果两个链表没有交点,返回 null.
  • 在返回结果后,两个链表仍须保持原有的结构。
  • 可假定整个链表结构中没有循环。
  • 程序尽量满足 O(n) 时间复杂度,且仅用 O(1) 内存。

如下面的两个链表

在节点 c1 开始相交。

2、示例

输入:intersectVal = 8, listA = [4,1,8,4,5], listB = [5,0,1,8,4,5], skipA = 2, skipB = 3
输出:Reference of the node with value = 8
输入解释:相交节点的值为 8 (注意,如果两个链表相交则不能为 0)。从各自的表头开始算起,链表 A 为 [4,1,8,4,5],链表 B 为 [5,0,1,8,4,5]。在 A 中,相交节点前有 2 个节点;在 B 中,相交节点前有 3 个节点。

3、题解

基本思想:双指针法,一开始想法受环形链表的启发,pA在headA链表不断绕圈,pB在headB链表不断绕圈,如果headA和headB之间有重合节点,pA和pB会在两个链表长度的最小公倍数的循环次数之前O(m*n)位于第一个重合节点处相遇。官方答案很巧妙,pA遍历headA链表结束后转到headB,pB遍历headB链表结束后转到headA,这样pA、pB在循环次数O(m+n)之前位于第一个重合节点处相遇。

#include<iostream>
#include<algorithm>
#include<vector>
using namespace std;
struct ListNode {
	int val;
	ListNode* next;
	ListNode(int x) : val(x), next(NULL) {}
};
void Init_ListNode(ListNode* headA, vector<int> vec1, int skipA, ListNode* headB, vector<int> vec2, int skipB)
{
	int i;
	ListNode* p1, * p2;
	p1 = headA;
	p1->val = vec1[0];
	p2 = headB;
	p2->val = vec2[0];
	for (i = 1; i < skipA; i++)
	{
		ListNode* q = new ListNode(vec1[i]);
		p1->next = q;
		p1 = p1->next;
	}
	for (i = 1; i < skipB; i++)
	{
		ListNode* q = new ListNode(vec2[i]);
		p2->next = q;
		p2 = p2->next;
	}
	for (; i < vec2.size(); i++)
	{
		ListNode* q = new ListNode(vec2[i]);
		p1->next = q;
		p1 = p1->next;
		p2->next = q;
		p2 = p2->next;
	}
	p1->next = NULL;
	p2->next = NULL;
}
class Solution {
public:
	ListNode* getIntersectionNode(ListNode* headA, ListNode* headB) {
		//基本思想:双指针法,一开始想法受环形链表的启发,pA在headA链表不断绕圈,pB在headB链表不断绕圈
		//如果headA和headB之间有重合节点,pA和pB会在两个链表长度的最小公倍数的循环次数之前O(m*n)位于第一个重合节点处相遇
		//官方答案很巧妙,pA遍历headA链表结束后转到headB,pB遍历headB链表结束后转到headA,这样pA、pB在循环O(m+n)之前位于第一个重合节点处相遇
		if (headA == NULL || headB == NULL)
			return NULL;
		ListNode* pA = headA, * pB = headB;
		while (pA != pB)
		{
			pA = pA == NULL ? headB : pA->next;
			pB = pB == NULL ? headA : pB->next;
		}
		return pA;
	}
};
class Solution1 {
public:
	ListNode* getIntersectionNode(ListNode* headA, ListNode* headB) {
		//优化的重要性,有许多地方可以优化
		if (headA == NULL || headB == NULL)
			return NULL;
		ListNode* pA, * pB, * endA, * endB;
		int lenA = 1, lenB = 1, count = 0;
		pA = headA;
		pB = headB;
		while (pA->next != NULL)
		{
			lenA++;
			pA = pA->next;
		}
		endA = pA;
		while (pB->next != NULL)
		{
			lenB++;
			pB = pB->next;
		}
		endB = pB;
		if (endA != endB)
			return NULL;
		pA = headA;
		pB = headB;
		while (count <= lenA * lenB)
		{
			if (pA == pB)
				return pA;
			if (pA == endA)
				pA = headA;
			else
				pA = pA->next;
			if (pB == endB)
				pB = headB;
			else
				pB = pB->next;
			count++;
		}
		return NULL;
	}
};
int main()
{
	Solution solute;
	ListNode* headA = new ListNode(0);
	ListNode* headB = new ListNode(0);
	int skipA = 2, skipB = 3;
	vector<int> vec1 = { 4,1,8,4,5 };
	vector<int> vec2 = { 5,0,1,8,4,5 };
	//初始化链表
	Init_ListNode(headA, vec1, skipA, headB, vec2, skipB);
	ListNode* p = solute.getIntersectionNode(headA, headB);
	if (p != NULL)
		cout << p->val << endl;
	else
		cout << "NULL" << endl;
	return 0;
}

 

 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值