單鏈表複製早已難不到你,但若我們再加個指標

2021-09-07 19:22:26 字數 2652 閱讀 8067

請實現複雜鍊錶的複製,在複雜鍊錶中,每個結點除了 next 指標指向下乙個結點外,還有乙個 sibling 指向鍊錶中的任意結點或者 null。比如下圖就是乙個含有 5 個結點的複雜鍊錶。

依舊是我們熟悉的第一步,先想好我們的測試用例:

輸入乙個 null ,期望什麼也不輸出;

輸入乙個結點,sibling 指向自身,期望列印符合題幹的值;

輸入多個結點,部分 sibling 指向 null,期望列印符合題幹的值。

測試用例思考完畢,自然是開始思考我們的測試邏輯了,在思考的過程中,我們不妨嘗試和面試官進行溝通,這樣可以避免我們走不少彎路,而且也容易給面試官留下乙個善於思考和溝通的好印象。

極易想到的邏輯是,我們先複製我們傳統的單鏈表,然後再遍歷單鏈表,複製 sibling 的指向。

假設鍊錶中有個結點 a,a 的 sibling 指向結點 b,這個 b 可能在 a 前面也可能在 a 後面,所以我們唯一的辦法只有從頭結點開始遍歷。對於乙個含有 n 個結點的鍊錶,由於定位每個結點的 sibling 都需要從煉表頭結點開始經過 o(n) 步才能找到,因此這種方法的時間複雜度是 o(n²)。

當我們告知面試官我們這樣的思路的時候,面試官告訴我們,他期待的並不是這樣的演算法,這樣的演算法時間複雜度也太高了,希望能有更加簡單的方式。

得到了面試官的訴求,我們再來看看我們前面的想法時間都花在哪兒去了。

很明顯,我們上面的想法在定位 sibling 指向上面花了大量的時間,我們可以嘗試在這上面進行優化。我們還是分為兩步:第一步仍然是先複製原始鍊錶上的每個結點 n 建立 n1,然後把這些建立出來的結點用 next 連線起來。同時我們把 的配對資訊放在乙個雜湊表中。第二步是設定複製鍊錶的 sibling 指向,如果原始鍊錶中有 n 指向 s,那麼我們的複製鍊錶中必然存在 n1 指向 s1 。由於有了雜湊表,我們可以用 o(1) 的時間,根據 s 找到 s1。

這樣的方法降低了時間成本,我們高興地與面試官分享我們的想法,卻被面試官指出,這樣的想法雖然把時間複雜度降低到了 o(n),但卻由於雜湊表的存在,需要 o(n) 的空間,而他所期望的方法是不占用任何輔助空間的。

接下來我們再換一下思路,不用輔助空間,我們卻要用更少的實際解決 sibling 的指向問題。

我們前面似乎對於指向都採用過兩個指標的方法,這裡似乎可以用類似的處理方式處理。

我們不妨利用原有鍊錶對每個結點 n 在後面直接在後面建立 n1,這樣相當於我們擴長原始鍊錶長度為現有鍊錶的 2 倍,奇數字置的結點連線起來是原始鍊錶,偶數字置的結點連線起來就是我們的複製鍊錶。

我們先完成第一部分的**。根據原始鍊錶的每個結點 n ,建立 n1,並把 n 的 next 指向 n1,n1 的 next 指向 n 的 next。

private static void clonenodes(node head)  } 

上面完成了複製結點,下面我們需要編寫 sibling 的指向複製。

我們的思想是:當 n 執行 s,那麼 n1 就應該指向 s1,即 n.next.sibling = n.sibling.next;

private static void connectnodes(node head)  // 遍歷 head = head.next.next; } } 

最後我們只需要拿出原本的鍊錶(奇數)和複製的鍊錶(偶數)即可。

private static node reconnectlist(node head)  return clonehead; } 

合併後的最終**就是:

public class test18  } private static node complexlistnode(node head)  private static void clonenodes(node head)  } private static void connectnodes(node head)  // 遍歷 head = head.next.next; } } private static node reconnectlist(node head)  return clonehead; } public static void main(string args)  private static boolean issamelink(node head, node root)  else  } return head == null && root == null; } private static void print(node head)  system.out.println("null"); while (temp != null)  } } 

寫畢**,我們驗證我們的測試用例。

輸入乙個 null ,也不會輸出,測試通過;

輸入乙個結點,sibling 指向自身,測試通過;

輸入多個結點,部分 sibling 指向 null,測試通過。

面試題:陣列中有乙個數字出現的次數超過陣列長度的一半,請找出這個數字並輸出。比如 中 2 的次數是 4,陣列長度為 7,所以輸出 2。要求不能修改輸入的陣列。

複雜單鏈表的複製

wz asust 2016 1 先int例項 後模板化 2 複製不能改變原串的資料及結構 3 隨機指標的正確性 思考 除了追加新結點後分離新舊鍊錶 還有一複雜度高的演算法,就是記錄下每乙個結點,隨機指標指向的結點在整個鏈中的排序 佇列實現 建立新煉表後,根據佇列記錄,連線隨機指標 不能記錄值,僅能實...

複雜單鏈表的複製

複雜單鏈表的複製 一 何為複製單鏈表 就我們所知,單鏈表也就是乙個結點包含乙個資料域和乙個指標域,這樣若干個結點構成的鍊錶。而複雜單鏈表和普通單鏈表差不多,唯一的不同就是多乙個random。我們可以用一張圖來表示 那我們怎麼來進行複雜鍊錶的複製呢,現在公認的最有效的方法只有一種,就是在原有單鏈表的每...

複雜單鏈表的複製

typedef struct complexlist complexlist,pcomplexlist void initlist pcomplexlist phead complexlist buynode datatype x 建立乙個複雜單鏈表 void insertnode pcomplex...