zoukankan      html  css  js  c++  java
  • 《剑指offer》-链表找环入口

    题目描述
    一个链表中包含环,请找出该链表的环的入口结点。

    初步想法是每个节点做几个标记,表示是否被访问过,那么遍历链表的时候就知道哪个被访问到了。但是不会实现。

    另一个直觉是判断链表有环的算法中出现过的策略,分别按1x和2x速度遍历,总会相遇。假设环长为n。
    容易知道,当1x的指针p1和2x的指针p2相遇时,p1走了x步,p2走了2x步,而p2比p1多走的,有两部分:(1)环内部,p1还没有走过的;(2)换内部,p1和p2重合的
    这两部分加起来就是整个环。那么其实p2比p1多走的就是这么一个环的距离,也就是说:

    2x-x = n  ==> n=x
    
    

    即:p1当前走了一个环长度的距离。

    下图表示了p1和p2相遇在B点的情况,其中A点开始顺时针方向回到A的轨迹就是环形,长度为n。

    不妨假设链表总长为L,那么:
    CA+A环=CA+n=L ==>L-n=CA
    CB=x=n=A环
    ==> BA弧=L-CB=L-n=CA

    也即:BA弧=CA,那么指针p1从B继续走,而指针p2从链表起点C从新开始(但是步长这次取1),则当p2到达A点时,p1也到达A点。
    对应到算法中,当1x和2x套圈时,p1和p2按照这个策略继续做while循环,直到再次相遇,就找到了环的入口。

    /*
    struct ListNode {
        int val;
        struct ListNode *next;
        ListNode(int x) :
            val(x), next(NULL) {
        }
    };
    */
    class Solution {
    public:
        ListNode* EntryNodeOfLoop(ListNode* pHead)
        {
            if(pHead==NULL){
                return NULL;
            }
            if(pHead->next==NULL){
                return NULL;
            }
            ListNode* p1=pHead;
            ListNode* p2=pHead;
            while(p2!=NULL && p2->next!=NULL){
                p1=p1->next;
                p2=p2->next->next;
                if(p1==p2){
                    p1 = pHead;
                    while(p1!=p2){
                        p1=p1->next;
                        p2=p2->next;
                    }
                    if(p1==p2){
                        return p1;
                    }
                }
            }
            return NULL;
        }
    };
    
  • 相关阅读:
    iosopendev配置
    按Home键切换到后台后会触发libGPUSupportMercury.dylib: gpus_ReturnNotPermittedKillClient导致crash
    iphone图片简单处理
    iPhone开发小工具
    iphone开发设置默认字体
    NSString+TimeCategory
    UIButton zoomin pressed
    Centos7下卸载docker
    如何清理Docker占用的磁盘空间
    美国VPS推荐1GB 50GB可以win
  • 原文地址:https://www.cnblogs.com/zjutzz/p/6506357.html
Copyright © 2011-2022 走看看