zoukankan      html  css  js  c++  java
  • 链表中环的入口结点

    链表中环的入口结点

    题目描述

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

    第一步两个节点, 一快一慢, 若有环则相遇

    当快慢节点相遇时, 慢结点走了x个节点, 快结点恰巧走了2x个节点, 2x = k*n + x, k为1, 2,..., 此时令其中一个节点等于头结点, 然后以相同速度移动两个节点, 相遇时恰好为环的入口节点

    class Solution {
    public:
        ListNode* EntryNodeOfLoop(ListNode* pHead)
        {
            if ((nullptr == pHead) || (nullptr == pHead->next)) {
                return nullptr;
            }
            ListNode *pNode1 = pHead;
            ListNode *pNode2 = pHead;
            
            while ((nullptr != pNode2) && (nullptr != pNode2->next)) {
                pNode1 = pNode1->next;
                pNode2 = pNode2->next->next;
                
                if (pNode1 == pNode2) {
                    pNode2 = pHead;
                    while (pNode1 != pNode2) {
                        pNode1 = pNode1->next;
                        pNode2 = pNode2->next;
                    }
                    return pNode1;
                }
            }
            return nullptr;
        }
    };
    

    利用快慢节点确定有无环若有则返回相交节点, 否则返回nullptr

    然后利用相交节点确定环的中节点的个数N

    再让一个节点指向头结点, 一个指针指向距头结点第N个节点, 然后以相同速度同时移动两个节点, 相遇时即为环的入口点

    class Solution {
    public:
        // 利用快慢节点移动速度不同, 若有环, 快慢节点必相遇
        ListNode *MeetingNode(ListNode* pHead) {
            if (nullptr == pHead) {
                return nullptr;
            }
            
            ListNode *pSlow = pHead->next;
            if (nullptr == pSlow) {    // 若只有两个节点则不能组成环
                return nullptr;
            }
            
            ListNode *pFast = pSlow->next;
            
            while((nullptr != pSlow) && (nullptr != pFast)) {
                if (pSlow == pFast) {
                    return pSlow;
                }
                pSlow = pSlow->next;
                //pFast = pSlow->next;    // 没有判断pFast移动后是否是空节点
                pFast = pFast->next;    // 需要判断pFast是不是空节点
                if (nullptr != pFast) {
                    pFast = pFast->next;
                }
            }
            
            return nullptr;
        }
        
        ListNode* EntryNodeOfLoop(ListNode* pHead)
        {
            ListNode *meetingNode = MeetingNode(pHead);
            if (nullptr == meetingNode) {
                return nullptr;
            }
            
            // 得到环节点的数目
            ListNode *ct = meetingNode;
            int counts = 1;
            while (ct->next != meetingNode) {
                counts++;
                ct = ct->next;
            }
            
            // 确定环的入口
            ListNode *pNode1 = pHead;    // pNode1指向头结点
            ListNode *pNode2 = pHead;    // pNode2先移动counts节点数目
            for (int i = 0; i < counts; i++) {
                pNode2 = pNode2->next;
            }
            while (pNode1 != pNode2) {
                pNode1 = pNode1->next;
                pNode2 = pNode2->next;
            }
            
            return pNode1;
        }
    };
    
    /*
    struct ListNode {
        int val;
        struct ListNode *next;
        ListNode(int x) :
            val(x), next(NULL) {
        }
    };
    */
    
  • 相关阅读:
    工业相机基础知识
    软件测试最常用的 SQL 命令 | 掌握基本查询、条件查询、聚合查询
    一文掌握软件测试常用SQL命令
    PageObject设计模式在 UI 自动化中的实践(QQ 邮箱登陆为例)
    测试开发必备--搞定PO设计模式
    Junit5 + YAML 参数化和数据驱动,让 App 自动化测试更高效(一)
    快速搞定APP移动端自动化测试
    接口自动化测试的 “能” 与 “不能”
    如何精通接口测试?
    测试开发必备:Dubbo-admin+Zookeeper 的环境搭建实操
  • 原文地址:https://www.cnblogs.com/hesper/p/10504838.html
Copyright © 2011-2022 走看看