面试题23:链表中环的入口节点

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/Sea_muxixi/article/details/82662011

题意:给一个链表,若其中包含环,请找出该链表的环的入口结点,否则,输出null。

思路:

方法一:把链表遍历一遍,如果没有重复节点,则没有环;如果有重复节点,第一个重复节点就是环的入口。

时间复杂度O(n),空间复杂度O(n)。

因为需要额外的数组去记录该节点有没有被访问过。

class Solution {
public:
	ListNode* EntryNodeOfLoop(ListNode* pHead)
	{
		ListNode* now = pHead;
		map<ListNode*, bool> vis;
		ListNode* ans = NULL;
		while (now != NULL)
		{
			if (vis[now] == false)
			{
				vis[now] = true;
			}
			else
			{
				ans = now;
				break;

			}
		}
		return ans;
	}
};

方法2:一快一慢两个指针,同时前进,如果相遇,则有环;不相遇,则无环。

对于有环的情况,在相遇节点,继续往前,再次回到相遇节点,这是经过的节点数就是环的节点数。

考虑总结点数为s,环中的节点数为n,那么非环的节点数为l=s-n;

所以只要从头结点遍历l个节点,那个节点就是环的入口;

或者也可以让一个指针先从头结点走n步,另一个指针再从头节点出发;

两个指针相遇的节点就是入口节点。

class Solution {
public:
	ListNode* EntryNodeOfLoop(ListNode* pHead)
	{
		if (pHead == NULL) return NULL;

		ListNode* meetNode = meet(pHead);
		if (meetNode == NULL) return NULL;

		

		int nodeCount = 1;
		ListNode* now = meetNode;
		while (now->next != meetNode)
		{
			now = now->next;
			nodeCount++;
		}

		ListNode* node1 = pHead;
		for (int i = 0; i < nodeCount; i++)
			node1 = node1->next;

		ListNode* node2 = pHead;
		while (node1 != node2)
		{
			node1 = node1->next;
			node2 = node2->next;
		}
		return node1;
	}
	ListNode* meet(ListNode* pHead)
	{
		if (pHead == NULL) return NULL;

		ListNode* slow = pHead->next;
		if (slow == NULL) return NULL;

		ListNode* fast = slow->next;

		while (slow != NULL && fast!=NULL)
		{
			if (slow == fast) return slow;

			slow = slow->next;
			if (fast->next != NULL && fast->next->next != NULL)
				fast = fast->next->next;
			else
				return NULL;

		}
		return NULL;
	}
};

猜你喜欢

转载自blog.csdn.net/Sea_muxixi/article/details/82662011