左神算法基础class3—题目14两个单链表相交的一系列问题

1.题目

【题目】 在本题中,单链表可能有环,也可能无环。给定两个单链表的头节点 head1和head2,这两个链表可能相交,也可能不相交。请实现一个函数, 如果两个链表相交,请返回相交的第一个节点;如果不相交,返回null 即可。 要求:如果链表1的长度为N,链表2的长度为M,时间复杂度请达到 O(N+M),额外空间复杂度请达到O(1)。

2.分析

总体思路是,先判断两个链表有没有环,如果两个链表都没有环(入环节点为空)再进行无环链表相交的求解;如果都有环(入环节点不为空)再进行有环链表相交求解。一个有环一个无环一定不相交。

(1)判断有无环:有环返回入环节点,无环返回空

思路1:使用哈希表,查找key是否进入map中;对head通过next进行遍历,如果没有则添加到map,如果存在则直接返回,最后next为空表示没有环。(具体实现待续)
思路2:不使用哈希表,准备两个快慢指针,快指针一次走两步,慢指针一次走一步。快指针走到空必然没有环,如果有环的话快慢指针一定相遇,快指针再从头开始,一次走一步,快慢指针一定在入环节点处相遇。

//判断有无环,思路二实现
List getLoopNode(List head)
{
	head = head->next;//从第一个节点开始
	//因为快指针需要走两步,两步内为空的必然无环
	if (head == NULL || head->next == NULL || 
		head->next->next == NULL)
			return NULL;
	//定义快慢指针
	List fast = head->next->next;
	List slow = head->next;
	
	while(fast != slow)
	{
		//快指针为空时直接返回不相遇
		if (fast == NULL || fast->next == NULL) 
			return NULL;
		//快指针一次走两步,慢指针一次走一步
		fast = fast->next->next;
		slow = slow->next;
	}
	//快指针返回开始位置
	fast = head;
	//第二次快指针一次走一步
	while(fast != slow)
	{
		fast = fast->next;
		slow = slow->next;
	}
	return fast;
}

(2)无环时求相交节点

对于两个链表,(1)中分析后都为null则是无环,无环情况下,接下来求相交节点。
思路1:使用map,把链表1放入map,遍历链表2,找到的第一个节点是第一个相交节点(具体实现待续)
思路2:不使用map,分别遍历链表1和链表2统计长度length、最后节点end。判断end1和end2内存地址是不是相同,如果不相同不可能相交。如果相同也不一定是第一个相交节点,重新遍历,让长的先走|length1 - length2|,两链再一起遍历,地址相同的第一个节点就是相交节点。

List noLoop(List head1,List head2)
{
	head1 = head1->next;
	head2 = head2->next;
	List cur1 = head1;
	List cur2 = head2;
	//计算length,存储最后一个节点
	int len1 = 0;
	int len2 = 0;
	List end1 = cur1;
	List end2 = cur2;
	while(cur1 != NULL)
	{
		end1 = cur1;
		len1++;
		cur1= cur1->next;
	}
	while(cur2 != NULL)
	{
		end2 = cur2;
		len2++;
		cur2= cur2->next ;
	}
	//找交点
	
	if(end1 != end2)//end1、end2是指针所指的地址相等
		return NULL;
	int dist = abs(len1 - len2);
	int count = 0;
	cur1 = len1 > len2 ? head1 : head2;//cur1是长链
	cur2 = len1 > len2 ? head2 : head1;//cur2是短链
	//先走多余的步数
	while(count < dist)
	{
		cur1 = cur1->next;
		count++;
	}
	while(cur1 != cur2)
	{
		cur1 = cur1->next;
		cur2 = cur2->next;
	}
	return cur1;//return cur2也可以
}

(3)有环时求相交节点

有环是指两个链表都有环,对于单链表一个链表有环一个链表无环的情况不可能出现相交的情况
那么有环链表相交可以归为3类,①两链不相交、②先相交再有环、③在环上相交。
这三种情况如下图,可以利用(1)中返回的有环节点来解。loop1 == loop2时也就是两个环的入环节点相同为情况②,此时抛去环部分,只看上部分就等同于无环链表相交问题即上述的(2)。而另一种情况是入环节点不同,使用loop1在环上遍历,在loop1遍历环一圈转回loop1的时候依旧没找到loop2说明两环不相交,是情况①;而在遍历过程中找到了loop2是情况③,返回loop1或者loop2都可以。

在这里插入图片描述

List bothLoop(List head1,List loop1, List head2,List loop2)
{
	head1 = head1->next;
	head2 = head2->next;
	//入环节点相同,等同于无环相交
	if(loop1 == loop2)
	{
		List cur1 = head1;
		List cur2 = head2;
		//计算length,存储最后一个节点
		int len1 = 0;
		int len2 = 0;
		//只讨论入环节点之前的部分
		while(cur1 != loop1)
		{
			len1++;
			cur1= cur1->next;
		}
		while(cur2 != loop2)
		{
			len2++;
			cur2= cur2->next ;
		}
		int dist = abs(len1 - len2);
		int count = 0;
		cur1 = len1 > len2 ? head1 : head2;
		cur2 = len1 > len2 ? head2 : head1;
		//先走多余的步数
		while(count < dist)
		{
			cur1 = cur1->next;
			count++;
		}
		while(cur1 != cur2)
		{
			cur1 = cur1->next;
			cur2 = cur2->next;
		}
		return cur1;
	}
	//入环节点不同
	else
	{
		List cur1 = loop1->next;
		while(loop1 != cur1)//只判断环之前的部分
		{
			if(cur1 == loop2)
			{
				return loop1;
			}
			cur1  = cur1 ->next ;
		}
		return NULL;
	}
}
发布了51 篇原创文章 · 获赞 1 · 访问量 1377

猜你喜欢

转载自blog.csdn.net/shi_xiao_xuan/article/details/103816431