美文网首页Python
python算法-014找出环的出口点(接013)

python算法-014找出环的出口点(接013)

作者: DKider | 来源:发表于2019-03-12 23:26 被阅读38次

    你今天晚了!
    你看看现在几点了?

    你的头发 。。

    感谢425以及身边的同学,给我的动力,让我完成了今天的任务。今天就把找环出口给写了吧!


    题目:给一个长度较大的链表,判断其是否有环存在,并找出环的出口点。例如:

    H->1->3->4->6->7->0->2->4
    1-          ^           |
                |           7
    2-          |           |
                |           v
    3-          7<-0<-2<-4<-3
    

    这里说下为什么要找环的出口:因为如果链表有环,在遍历链表或者释放链表所占空间时,会很麻烦,如果我们知道了环的出口,就会变得很简单。

    013的两种方法都可以实现判断是否有环,接下来就是找到环的出口,接着看着个字符图:

    H->1->3->4->6->7->0->2->4
    1-          ^           |
                |           7
    2-          |           |
                |           v
    3-          7<-0<-2<-4<-3
    
    图中的节点6就是我们要找的出口。根据我们找环方式的不同,判断其出口就有略微的差别:

    用蛮力法的话,在判断其是否相等时,就可以得到,相等的那个点就是我们要找的出口,返回这个节点就可以了。这代码简单,013代码加一行return 就能完成就不写了。

    如果用快慢指针法,就有点差别。比如下面的情况:

             f4
       f1    f2
          s6 s7
       s1 s2 s3        s代表slow,f代表fast,
       |  |  |         边上的数字代表遍历的次数
       V  V  V   
                       根据要求:每次遍历作比较
    H->1->2->3         也就是遍历次数相同的作比较
          ^  |         我把s放在内层了,从图上来看,
          |  V         是在第5次遍历完成的判断,此时
          5<-4 <—s4   
     
          ^
          |
          s5
          f3
          f5
    

    由此看来,这不是有点差别,差别还不小了。这还只是5个节点,那如果更大怎么办?
    当有环时:
    slow走的比fast慢,所以slow在与fast相遇时,slow一定没有遍历完链表,而fast已经进入环的循环,设slow遍历过了s个节点,则fast遍历了2s个。设fast在环里面转了n圈了,n>=1。设环的长度为r个节点,出口是第a个节点,当slow与fast相遇时的节点是第x个节点,链表长度为L。接下来就是数学题了,怎样解x?
    高中数学学的不错的我,一眼看出了答案呢,你呢?
    我大学学会了吹NB。。。
    以下的推导过程还要感谢我的室友NJF同学:
    fast走的步数还等于s+n*r,所以有:
    2s=s+n*r=>s=n*r
    又:a+x=nr
    a+x=(n-1)*r+r=(n-1)*r+L-a
    a=(n-1)*r+(L-a-x)
    L-a-x为相遇点到环入口的距离
    a=(n-1)*r+(L-a-x)这个式子的意义就是:链表头到环入口的距离=(n-1)*环长+相遇点到环入口的距离。
    所以从链表头设一指针A,相遇点设一指针B,同时遍历,每次一步,必定相遇,且相遇点为入口点!
    这太神奇了!感谢JF。
    代码:

    import random
    import time
    class LNode:
        def __init__(self,arg):
            self.data=arg
            self.next=None
    
    """
    题目描述:
    链表中的某个节点的next域指向的是链表中在他之前的某一个节点,这样在链表尾部形成了环的结构。如何判断链表中是否有环的结构
    要求:
    方法:HashSet蛮力法
    """
    def constructLinkwithAnnulation(x):
        i = 1
        head = LNode(None)
        tmp = None
        cur = head
        while i <= x:
            n = random.randint(1, 9)
            tmp = LNode(n)
            cur.next = tmp
            cur = tmp
            i += 1
        # 上面的部分 就是之前我们用的构造链表的方法
        #这里我是设置了二分之一的概率产生有环的链表
        if random.randint(0,1)==0:
            m = random.randint(1, x - 1)  # 用于选择出环的入口是哪个
            Annulation=head.next # 用于遍历到选定的节点,就是出环的入口
            while m>0:
                Annulation=Annulation.next
                m-=1
            # 因为前面构造链表时就用了cur,最后他指向了最后一个节点
            cur.next=Annulation #这里将尾结点的next域指向环入口
        return head
    def judgeAnnulation(head):
        #判断链表是否为空
        if head.next is None or head.next is None:
            return None
        #都指向第一个节点
        slow=head.next
        fast=head.next
        #开始遍历
        while fast is not None:
            #这里注意一定先操作再判断,因为如果先判断的话,
            # 第一个节点就是相等的
            slow = slow.next
            fast = fast.next.next
            if slow==fast:
                #这里直接判断两个节点是否完全相等,返回节点
                return slow
        return False
    
    def Finddoor(head,meetNode):
        A=head.next
        B=meetNode
        while A is not B:
            A=A.next
            B=B.next
        return B
    
    if __name__ == '__main__':
        start = time.time()
        head = constructLinkwithAnnulation(1000000)
        end = time.time()
        print("创建用时:", end - start)
        cur = head.next
        start1=time.time()
        buer=judgeAnnulation(head)
        end1=time.time()
        print("判断用时:",end1-start1)
    
        if buer == False:
            print("head中没环")
        elif buer==None:
            print("head为空")
        else:
            print("head中有环,出口为:")
            print(Finddoor(head,buer).data)
    
    1000000 1000000

    感谢大家对我的监督,我会努力的,不管掉不掉头发!

    加油!

    相关文章

      网友评论

        本文标题:python算法-014找出环的出口点(接013)

        本文链接:https://www.haomeiwen.com/subject/cxtapqtx.html