簡體   English   中英

Cracking the Coding Interview,第6版,2.8

[英]Cracking the Coding Interview, 6th edition, 2.8

問題陳述:給定一個循環鏈表,實現一個在循環開始時返回節點的algoirthm。

答案密鑰提供了比我建議的更復雜的解決方案。 我有什么問題?:

public static Node loopDetection(Node n1) {
    ArrayList<Node> nodeStorage = new ArrayList<Node>();

   while (n1.next != null) {
       nodeStorage.add(n1);
       if (nodeStorage.contains(n1.next)) {
           return n1;
       }
       else {
           n1 = n1.next;
       }
   }

   return null;
}

你的解決方案是O(n^2)時間( ArrayList每個contains()O(n)時間)和O(n)空間(用於存儲nodeStorage ),而“更復雜”的解決方案是O(n)時間和O(1)空間。

本書為感興趣的人提供了以下解決方案,即O(n)時間和O(1)空間:

如果我們移動兩個指針,一個速度為1,另一個速度為2,如果鏈表有循環,它們將會結束。 為什么? 想想兩輛在賽道上行駛的汽車 - 速度越快的汽車總會越過越慢! 這里棘手的部分是找到循環的開始。 想象一下,作為一個類比,兩個人在賽道上比賽,一個賽跑的速度是另一個賽車的兩倍。 如果他們在同一個地方開始,他們下一次會什么時候見面? 接下來他們將在下一圈開始時見面。 現在,讓我們假設Fast Runner在n步圈上有一個k米的起跑線。 他們什么時候下次見面? 他們將在下一圈開始前達到k米。 (為什么?快跑者會做出k + 2(n-k)步,包括它的頭部開始,慢跑者會做n-k步。兩者都將在循環開始之前的k步。)現在,去回到問題,當Fast Runner(n2)和Slow Runner(n1)在我們的循環鏈表中移動時,當n1進入時,n2將在循環上有一個開頭。 具體來說,它將具有k的頭部起點,其中k是循環之前的節點數。 由於n2具有k個節點的頭部起始,因此n1和n2將在循環開始之前與k個節點相遇。 因此,我們現在知道以下內容:1。Head是來自LoopStart的k個節點(根據定義)。 2. MeetingPoint for n1和n2是來自LoopStart的k個節點(如上所示)。 因此,如果我們將n1移回Head並在MeetingPoint保持n2,並以相同的速度移動它們,它們將在LoopStart上相遇。

LinkedListNode FindBeginning(LinkedListNode head) {
   LinkedListNode n1 = head;
   LinkedListNode n2 = head;

   // Find meeting point
   while (n2.next != null) {
      n1 = n1.next;
      n2 = n2.next.next;
      if (n1 == n2) {
         break;
      }
   }
// Error check - there is no meeting point, and therefore no loop
   if (n2.next == null) {
      return null;
   }
   /* Move n1 to Head. Keep n2 at Meeting Point. Each are k steps
   /* from the Loop Start. If they move at the same pace, they must
   * meet at Loop Start. */
   n1 = head;
   while (n1 != n2) {
      n1 = n1.next;
      n2 = n2.next;
   }
   // Now n2 points to the start of the loop.
   return n2;
   }

amit給出了解決方案。 問題是你要么知道要么你不知道,但你不能在面試中弄明白。 由於我從來沒有需要在鏈表中找到一個循環,除了通過面試之外,了解它對我來說毫無意義。 所以對於面試官來說,這是一個面試問題,並期待amir的回答(這很好,因為它有線性時間和零額外空間),這是非常愚蠢的。

所以你的解決方案大多沒問題,除了你應該使用哈希表,你必須確保哈希表散列對節點而不是節點的引用 假設您有一個包含字符串和“下一個”指針的節點,並且哈希函數對字符串進行哈希處理,並且如果字符串相等則將節點比較為相等。 在這種情況下,你會發現第一個節點有一個重復的字符串,而不是循環開始時的節點,除非你小心。

(amir的解決方案在語言中有一個非常類似的問題,其中==比較對象,而不是引用。例如在Swift中,你必須使用===(比較引用)而不是==(比較對象))。

我無法直觀地看到這個算法發生了什么。 希望這有助於其他人。

在時間t = k(3),p2是從頭部(0)到p1的距離的兩倍,所以為了使它們重新排成一行,我們需要p2'趕上'到p1,它將需要L - k( 8)還有5個步驟發生。 p2以p1的速度行進2倍。

在時間t = k +(L-k)(8),p2需要向前行進k步以返回到k。 如果我們將p1重置回頭部(0),我們知道如果p2以與p1相同的速度行進,則p1和p2都將在k(3,19分別)處相遇。

鏈接列表圖形

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM