链表-2 链表中环的入口节点

解法1:循环(空间复杂度非O(1))

        思路是:从头开始遍历每个节点,并把每个已访问节点存入“已访问节点列表”visited_Node中。

        当最新访问的节点在“已访问节点列表”中出现时,则最新访问的节点为该链表中环的入口;若整个链表的节点都没出现在““已访问节点列表””中,则该链表无环。

class Solution:
  def EntryNodeOfLoop(self, pHead):
    visited_Node = [];
    if pHead is None:
      return None;
    while pHead is not None:
      if pHead in visited_Node:
        return pHead;
      visited_Node.append(pHead);
      pHead = pHead.next;
    return None;
运行时间:27ms
占用内存:5852k

         缺点:需要定义额外的存储空间,存“已访问节点列表”。

解法2:快慢指针法+双指针法(未想到,空间复杂度O(1))

        思路是:拆解问题。将“求链表中环的入口节点”拆分为3个小问题:

               ①确定链表中是否有环(快慢指针法);

               ②若有环,则需找到环中的任意一个节点p,并确定环中的总节点个数;

               ③从节点p开始,找到环的入口节点(双指针法)。

class Solution:
    def EntryNodeOfLoop(self, pHead):
        if pHead is None or pHead.next is None:
            return None;
        else:
            # 1.确定链表中是否有环(快慢指针法)
            p_slow = pHead.next;
            p_fast = pHead.next.next;
            while p_fast != p_slow:
                if p_fast is None:
                    return None;
                p_slow = p_slow.next;
                p_fast = p_fast.next.next;
            p = p_fast;  # p记录的是慢指针和快指针相遇时对应的那个链表节点;
                         # p节点若存在,则必定在环中。
            # 2.计算环中的总节点个数k
            k = 1;
            p_flag = p.next;
            while p_flag != p:
                k = k + 1;
                p_flag = p_flag.next;
            # 3.确定环的入口(双指针法,做法:令指针p1从头结点先多走k步,此时p1到达第(1+k)个节点;然后令指针p2从头节点开始走,指针p1、p2的前进速度相同。当指针p1、p2相遇时,它们指向的节点恰好为环的入口结点。
            # 未想到的点:指针p2从头结点走到环的入口节点,走了(n-k)步;此时指针p1到达的位置为(k+1)+(n-k)=(n+1),即为环的入口节点,p1、p2正好相遇。)
            i = 0;
            p1 = pHead;
            while i < k:
                p1 = p1.next;
                i = i+1;
            p2 = pHead;
            while p1 != p2:
                p1 = p1.next;
                p2 = p2.next;
            return p2;

第一次运行 解法2:
    运行时间:31ms
    占用内存:5816k
第二次运行 解法2:
    运行时间:28ms
    占用内存:5748k

 

posted @ 2020-02-19 15:25  花与  阅读(77)  评论(0)    收藏  举报