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;
        }
    };
    
  • 相关阅读:
    【Android】Android连接SQLite3数据库的操作
    【exe4j】如何利用exe4j把java桌面程序生成exe文件
    Http网络协议
    【Spring】spring的7个模块
    【jsp】JSP中page指令isThreadSafe
    【MySQL】乐观锁和悲观锁
    【Eclipse】Eclipse上如何集成SVN插件
    【MySQL】mysql出现错误“ Every derived table must have its own alias”
    【Struts2】SSH如何返回JSON数据
    【Oracle】Oracle 的过程化SQL(PLSQL)中NULL值的处理
  • 原文地址:https://www.cnblogs.com/zjutzz/p/6506357.html
Copyright © 2011-2022 走看看