• 链表中环的入口结点


    时间限制:C/C++ 1秒,其他语言2秒 空间限制:C/C++ 32M,其他语言64M

    题目描述

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

    思路:

    设置快慢指针都从链表头出发,快指针每次走两步,慢指针每次走一步,假如有环,一定可以相遇于环中某点(结论1)。接着让两个指针分别从相遇点和链表头出发,两者都改为每次走一步,最终相遇于环入口(结论2)。对上述两个结论,以下进行了证明:
    两个结论:
    1.设置快慢指针,假如有环,最终他们必相遇。
    2.两个指针分别从链表头和相遇点继续出发,每次走一步,最终一定相遇于环入口。

    证明结论1:设置快慢指针fast和low,fast每次走两步,low每次走一步。假如有环,两者一定会相遇(因为low一旦进入环中,可视为fast在后面追赶low的过程,每次两者都接近一步,最后一定能相遇)。
    证明结论2:
    设:
    链表头到环入口长度为a,
    环入口到相遇点长度为b,
    相遇点到环入口长度为c

    则:相遇时
    快指针路程 = a+(b+c)k+b,k>=1 其中b+c为环的长度,k为绕环的圈数(K >= 1,即最少一圈,不能是0圈,不然和慢指针走到一样长,矛盾)
    慢指针路程 = a + b
    快指针走的路程是慢指针的两倍,所以:
    (a + b) * 2= a+(b+c)k + b
    化简可得:
    a = (k-1)(b+c)+c,即链表头到环入口的长度等于相遇点到环入口的距离+(k-1)倍的环长度。其中K>=1,所以k-1>=0圈,所以两个指针分别从链表头和相遇点出发,每次走一步,最终一定相遇于环入口。

    /*
    struct ListNode {
        int val;
        struct ListNode *next;
        ListNode(int x) :
            val(x), next(NULL) {
        }
    };
    */
    class Solution {
    public:
        ListNode* EntryNodeOfLoop(ListNode* pHead)
        {
            ListNode* fast = pHead,*low = pHead;
            while(fast && fast->next)
            {
                fast = fast ->next->next;
                low = low->next;
                if(low == fast)
                    break;
            }
            if(!fast || !fast->next)
                return NULL;
            low = pHead;
            while(fast != low)
            {
                fast = fast->next;
                low = low->next;
            }
            return low;
        }
    };
    

    还有一种方法,虽然对原本的数据结构进行了破坏,但对本题不乏是一种新奇有效的解法
    设立两个指针,一个在左(previous),一个在右(front),previous指针紧跟front指针,每向前移动时就将previous指针的next赋为NULL,此时已经将数据结构损坏,最后将previous所指向的即为所求。

    /*
    struct ListNode {
        int val;
        struct ListNode *next;
        ListNode(int x) :
            val(x), next(NULL) {
        }
    };
    */
    class Solution {
    public:
        ListNode* EntryNodeOfLoop(ListNode* pHead)
        {
            if(!pHead->next)
            {
                return NULL;
            }
            ListNode* previous = pHead;
            ListNode *front = pHead->next;
            while(front)
            {
                previous->next = NULL;
                previous = front;
                front = front->next;
            }
            return previous;
        }
    };
    
    

    由于对原始数据结构存在破坏,所以在实际中也许存在一定的争议。

  • 相关阅读:
    基于HSharp使用C#对象建立并输出HTML
    基于HSharp 使用C#反序列化HTML并获取HTML中的特定内容
    iis最大连接数和队列长度
    强网拟态 2021 showyourflag Writeup
    ByteCTF 2021 bytecert Writeup
    基于 OpenSSL 的 RSA 消息加密及签名实现
    思维导图-2020的目标
    我的第一个博客
    【网络流24题】洛谷P4015 运输问题
    CSP/NOIP 防爆指南
  • 原文地址:https://www.cnblogs.com/whiteBear/p/12676439.html
Copyright © 2020-2023  润新知