两个单链表相交的一系列问题c++

题目

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

分析

这道题涵盖了链表相交的一系列问题 也是左老师直播课的内容,我们可以拆分成几个问题来分步处理,

  1. 首先判断单链表是否有环,这里我们给该函数增加一个功能,如果有环则返还该链表的入口结点,没有则返回NULL.
  2. 判断两个无环链表是否相交,如果相交则返回相交节点,否则返回NULL。
  3. 判断两个有环链表是否相交,如果相交则返回相交节点,否则返回NULL。
  4. 如果一个链表有环,一个无环则则不相交返回NULL;

问题一

采用快指针慢指针的方法,具体操作是,定义一个快指针和一个慢指针,从头结点开始,快指针一次走两步,慢指针一次走一步,(如果走到某一步快指针为NULL,说明它到头了,进而说明它没形成环,返回NULL)如果快指针和 慢指针相遇了,说明是有环的,此时让快指针从新回到头结点,并且调整步伐为每一一步,和慢指针同步,当它们再次相遇时,所处的位置就是入环结点,这就是个套路,知道这么用就好了。这部分代码如下:

Node*getNode(Node*head)
{
	if (head == NULL)
		return NULL;
	Node*slow = head->next;
	Node*fast = head->next->next;
	while (fast != slow) {
		if (fast->next == NULL || fast->next->next == NULL)
		{
			return NULL;

		}
		fast = fast->next->next;
		slow = slow->next;
	}
	fast = head;
	while (fast != slow)
	{
		fast = fast->next;
		slow = slow->next;
	}
	return fast;
}

问题二

两个无环链表相交,结构就是一个Y字形,我们将两个链表各自遍历一遍,求出长度相减,就知道两个链表的相差长度,让长链表独自走相差出来的长度的距离,然后此时两个链表在同一起跑线了,同时往下走,直到结点相等,也就是他们首次相遇的地方。

Node*noLoop(Node*head1, Node*head2)
{
	int n = 0;
	Node*n1 = head1;
	Node*n2 = head2;
	while (n1 != NULL)
	{
		n++;
		n1 = n1->next;
	}
	while (n2 != NULL)
	{
		n--;
		n2 = n2->next;
	}
	n1 = n > 0 ? head1 : head2;
	n2 = n1 == head1 ? head2 : head1;
	n = abs(n);
	while (n!=0)
	{ 
		n--;
		n1 = n1->next;
	}
	while (n1 != n2)
	{
		n1 = n1->next;
		n2 = n2->next;
	}
	return n1;

}

问题三

两个有环链表 一共三种形态:
在这里插入图片描述
可以通过入口结点是否相等当做边界条件来分析,当loop1=loop2时是图2的情况,跟两个无环链表相交的情况基本一致,有一点注意就是遍历链表求长度时只需要求到入口结点的长度,将下面的环砍掉,剩下的就和问题二一致。
当loop2不等于loop1时有可能是图一也有能是图二,这时让loop1结点往下遍历,并每次查看是否能等于loop2如果有等于说明是图3这时返回loop1或者loop2都可以,如果走了一圈还没碰到lloop2,说明是图1没有相交返回NULL;

Node*loop(Node*head1, Node*loop1, Node*head2, Node*loop2)
{
	Node *n1 = NULL;
	Node *n2 = NULL;
	if (loop1 == loop2)
	{
		int n = 0;
		n1 = head1;
		n2 = head2;
		while (n1 != loop1)
		{
			n++;
			n1 = n1->next;
		}
		while (n2 != loop2)
		{
			n--;
			n2 = n2->next;
		}
		n1 = n > 0 ? head1 : head2;
		n2 = n1 == head1 ? head2 : head1;
		n = abs(n);
		while (n!=0)
		{
			n--;
			n1 = n1->next;
		}
		while (n1 != n2)
		{
			n1 = n1->next;
			n2 = n2->next;
		}
		return n1;
	}
	else {
		n1 = loop1->next;
		while (n1 != loop1)
		{
			if (n1 == loop2)
				return loop1;
			n1 = n1->next;
		}
		return NULL;
	}


}

总体代码如下

// 两个单链表相交的一系列问题.cpp : 定义控制台应用程序的入口点。
//
//【题目】 在本题中, 单链表可能有环, 也可能无环。 给定两个
//单链表的头节点 head1和head2, 这两个链表可能相交, 也可能
//不相交。 请实现一个函数, 如果两个链表相交, 请返回相交的
//第一个节点; 如果不相交, 返回null 即可。 要求: 如果链表1
//的长度为N, 链表2的长度为M, 时间复杂度请达到 O(N + M), 额外
//空间复杂度请达到O(1)
#include "stdafx.h"
#include<iostream>
using namespace std;

struct Node
{
	int val;
	struct Node*next;
	Node(int data) :val(data),next(nullptr){}
};


Node*getNode(Node*head)
{
	if (head == NULL)
		return NULL;
	Node*slow = head->next;
	Node*fast = head->next->next;
	while (fast != slow) {
		if (fast->next == NULL || fast->next->next == NULL)
		{
			return NULL;

		}
		fast = fast->next->next;
		slow = slow->next;
	}
	fast = head;
	while (fast != slow)
	{
		fast = fast->next;
		slow = slow->next;
	}
	return fast;
}
Node*noLoop(Node*head1, Node*head2)
{
	int n = 0;
	Node*n1 = head1;
	Node*n2 = head2;
	while (n1 != NULL)
	{
		n++;
		n1 = n1->next;
	}
	while (n2 != NULL)
	{
		n--;
		n2 = n2->next;
	}
	n1 = n > 0 ? head1 : head2;
	n2 = n1 == head1 ? head2 : head1;
	n = abs(n);
	while (n!=0)
	{ 
		n--;
		n1 = n1->next;
	}
	while (n1 != n2)
	{
		n1 = n1->next;
		n2 = n2->next;
	}
	return n1;

}
Node*loop(Node*head1, Node*loop1, Node*head2, Node*loop2)
{
	Node *n1 = NULL;
	Node *n2 = NULL;
	if (loop1 == loop2)
	{
		int n = 0;
		n1 = head1;
		n2 = head2;
		while (n1 != loop1)
		{
			n++;
			n1 = n1->next;
		}
		while (n2 != loop2)
		{
			n--;
			n2 = n2->next;
		}
		n1 = n > 0 ? head1 : head2;
		n2 = n1 == head1 ? head2 : head1;
		n = abs(n);
		while (n!=0)
		{
			n--;
			n1 = n1->next;
		}
		while (n1 != n2)
		{
			n1 = n1->next;
			n2 = n2->next;
		}
		return n1;
	}
	else {
		n1 = loop1->next;
		while (n1 != loop1)
		{
			if (n1 == loop2)
				return loop1;
			n1 = n1->next;
		}
		return NULL;
	}


}
Node*getIntersectNode(Node*head1, Node*head2)
{
	if (head1 == NULL || head2 == NULL)
		return NULL;
	Node*Loop1 = getNode(head1);
	Node*Loop2 = getNode(head2);
	if (Loop1 == NULL&&Loop2 == NULL)
	{
		return noLoop(head1, head2);
	}
	else if (Loop1 != NULL&&Loop2 != NULL)
	{
		return loop(head1, Loop1, head2, Loop2);
	}
	return NULL;
}
int main()
{
	Node *head1 = new Node(1);
	head1->next = new Node(2);
	head1->next->next = new Node(3);
	head1->next->next->next = new Node(4);
	head1->next->next->next->next = new Node(5);
	Node *head2 = new Node(0);
	head2->next = new Node(9);
	head2->next->next = new Node(8);
	head2->next->next->next = head1->next->next->next;
	int a = getIntersectNode(head1, head2)->val;
	cout << a << endl;

	head1 = new Node(1);
	head1->next = new Node(2);
	head1->next->next = new Node(3);
	head1->next->next->next = new Node(4);
	head1->next->next->next->next = new Node(5);
	head1->next->next->next->next->next = new Node(6);
	head1->next->next->next->next->next->next = new Node(7);
	head1->next->next->next->next->next->next = head1->next->next->next;//7->4

	head2 = new Node(0);
	head2->next = new Node(9);
	head2->next->next = new Node(8);
	head2->next->next->next = head1->next; // 8->2
	/*int f = getNode(head2)->val;
	cout << f << " " << endl;*/

	int b = getIntersectNode(head1, head2)->val;
	cout << b<< endl;

	head2 = new Node(0);
	head2->next = new Node(9);
	head2->next->next = new Node(8);
	head2->next->next->next = head1->next->next->next->next->next;
	int c = getIntersectNode(head1, head2)->val;
	cout << c << endl;
    return 0;
}


发布了47 篇原创文章 · 获赞 3 · 访问量 1433

猜你喜欢

转载自blog.csdn.net/weixin_42076938/article/details/104607491