第23题:链表中环的入口结点

题目描述

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

考点

1.鲁棒性:存在环;不为空链表;指针下一个节点存在时才往下走。

2.复杂问题分解成简单问题 。

 

思路

1.判断链表中存在环:

两个指针,同时从头节点出发,fast的走两步,slow的走一步。

如果fast追上了slow,则说明存在环。

如果fast走到了末尾,fast->next==nullptr,fast都没有追上slow,说明不存在环。

 

2.判断环的入口:

如果环中有n个节点,fast和slow同时从head出发,先让fast走n步,然后slow和fast一个速度走。

如果slow和fast相遇了,此时相遇的节点就是环的入口。

 

3.计算环的个数:

第一步判断是否有环时,相遇的节点一定在这个环中,从这个节点开始走,并且计数,如果回到了该节点,就是环的节点个数。

 

 

 

 第一遍

//鲁棒性:是否存在环
ListNode* MeetingNode(ListNode* pHead)
{
	//1.鲁棒性1:头节点为空,返回空
	if (!pHead)
		return nullptr;

	//2.slow先走一步,注意鲁棒性2: 如果slow不存在返回nullptr
	ListNode* slow = pHead->m_pNext;
	if (!slow)
		return nullptr;

	//3.fast走两步
	ListNode* fast = slow->m_pNext;

	//4.如果fast和slow都存在的情况
	while (fast&& slow)
	{
		//4.1 如果两个指针相遇了,返回相遇节点
		if (fast == slow)
			return fast;

		//4.2 slow先走到下一步
		slow = slow->m_pNext;

		//4.3 fast要走两步,先走第一步,在测试鲁棒性之后,走第二部
		fast = fast->m_pNext;
		if (fast)
		{
			fast = fast->m_pNext; 
		}
	}

	//5.如果fast和slow都没有相遇,返回nullptr
	return nullptr;
}

//找到入口
ListNode* EntryNodeOfLoop(ListNode* pHead)
{
	//1.鲁棒性检查:判断是否含有环,如果没有,返回空
	ListNode* MeetNode = MeetingNode(pHead);
	if (!MeetNode)
		return nullptr;

	//2.设置环内节点计数参数,从1开始
	int count = 1;

	//3.新建一个指针从相遇节点的下一个走
	ListNode* Node = MeetNode->m_pNext;
	
	//4.边走边计数,走到遇到自己为止,
	while (Node&& (Node != MeetNode))
	{
		Node = Node->m_pNext;
		count++;
	}
	Node = nullptr;

	//5.先让fast走n步
	ListNode* fast= pHead;
	for(int i=0;i<count;i++)
	{ 
		fast= fast->m_pNext; 
	}

	//6.slow开始走
	ListNode* slow = pHead;
	while (slow&&fast)
	{
		if (slow == fast)
			return fast;

		slow = slow->m_pNext;
		fast = fast->m_pNext;
	}



}

 

 

第二遍

/*
struct ListNode {
    int val;
    struct ListNode *next;
    ListNode(int x) :
        val(x), next(NULL) {
    }
};
*/
class Solution {
public:
    //检查是否有环,并返回环中的节点
    ListNode* MeetingNode(ListNode* pHead)
    {
        //1.鲁棒性测试1:空链表
        if(!pHead)
            return nullptr;
        //2.鲁棒性2:头节点的next为空
        if(!pHead->next)
            return nullptr;
        
        //3.定义slow和fast,同时出发,slow走一步,fast走两步
        ListNode* slow=pHead->next;
        ListNode* fast=slow->next;
        
        //4.鲁棒性3:fast走到第二部如果不存在
        if(!fast)
            return nullptr;
        
        //5.while循环条件:fast和slow都存在的情况
        while(fast&&slow)
        {
            //5.1 如果相遇,返回相遇点
            if(fast==slow)
                return fast;
            //5.2 slow走一步
            slow =slow->next;
            
            //5.3 fast走两步,先判断走的第一步是否为空,如果为空,就不是循环列表,也不能走第二步,返回
            fast=fast->next;
            if(!fast)
                return nullptr;
            else
                fast=fast->next;
            
        }
        
        //6. 如果没有相遇,返回空
        return nullptr;
        
        
    }
    
    //找到环中的入口
    ListNode* EntryNodeOfLoop(ListNode* pHead)
    {
        //1.如果不存在环,返回空
        ListNode* meetNode= MeetingNode(pHead);
        if(!meetNode)
            return nullptr;
        
        //2.计算环的节点个数
        int count=1;
        ListNode* node=meetNode->next;
        while(node!=meetNode)
        { 
            node=node->next;
            count++;
        }
        node=nullptr;
        
        //3.寻找入口节点
        ListNode* fast = pHead;
        ListNode* slow = pHead;
        //3.1 fast先走N步
        for(int i=0;i<count;i++)
        {
            fast=fast->next;
        }
        
        //3.2 slow开始走,如果fast和slow相遇了就是环的入口
        while(slow!=fast)
        {
            slow= slow->next;
            fast=fast->next;
        }
        
        return fast;
    }
    
    
};

注意:如果有循环链表是不会到nullptr的,所以不用判断nullptr了。

posted @ 2019-02-06 23:36  lightmare  阅读(147)  评论(0编辑  收藏  举报