环形链表 II 的两种方法(哈希、双指针)

简单的判断环形链表
环形链表 II(找出循环的节点)

给定一个链表,返回链表开始入环的第一个节点。 如果链表无环,则返回 null。

一、哈希

我们遍历链表中的每个节点,并将它记录下来;一旦遇到了此前遍历过的节点,就可以判定链表中存在环。借助哈希表可以很方便地实现。

class Solution {
    
    
public:
	ListNode* detectCycle(ListNode* head) 
	{
    
    
		unordered_set<ListNode*> visited;
		while (head != NULL) 
		{
    
    
			if (visited.count(head)) 
			{
    
    
				return head;
			}
			visited.insert(head);
			head = head->next;
		}
		return NULL;
	}
};

双指针

算法流程:

设置两个指针,快指针fast,慢指针slow。

第一种结果:fast走过链表末端,说明链表无环,直接返回NULL

第二种结果,两指针在环中 第一次相遇。我们来分析步数关系:

设链表有x+y个节点。其中 链表头部到链表入口 有 x 个节点(不计链表入口节点), 链表环 有 y 个节点;设两指针分别走了 f,s 步,则有

f=2s (因为快指针走的每轮比慢指针多一步)

f=s+ny(双指针都走过 x 步,然后在环内绕圈直到重合,重合时快指针比慢指针多走环长度的整数倍,假定为n)

两式相减得f=2ny,s=ny,即f,s各自走了,2n,n个环的周长。

此时将快指针重新设置为指向头节点,s,f指针每轮向前走一步。

f=0,s=ny

当f=x时,s=ny+x,两指针重合,并同时指向链表环入口 。

class Solution {
    
    
public:
	ListNode* detectCycle(ListNode* head) 
	{
    
    
		ListNode* slow = head, * fast = head;
		while (fast != NULL && fast->next != NULL)
		{
    
    
			slow = slow->next;
			fast = fast->next->next;
			if (fast == slow)
				break;
		}
		if (fast == NULL || fast->next == NULL) return NULL;
		ListNode* ptr = head;
		while (ptr != slow)
		{
    
    
			ptr = ptr->next;
			slow = slow->next;
		}
		return ptr;
	}
};

猜你喜欢

转载自blog.csdn.net/weixin_45605341/article/details/108991039