zoukankan      html  css  js  c++  java
  • 第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了。

  • 相关阅读:
    Gitee + PicGo搭建图床 & Typora上传图片到图床
    算法思维 ---- 双指针法
    Floyd's cycle-finding algorithm
    Boyer-Moore Voting Algorithm
    youtube-dl 使用小记
    算法思维 ---- 滑动窗口
    Memo
    英语
    BZOJ 3270
    BZOJ 3196
  • 原文地址:https://www.cnblogs.com/lightmare/p/10398757.html
Copyright © 2011-2022 走看看