谷歌面試題:如何從無序鏈表中移除重複項?

一位小夥伴來問一道谷歌的筆試題,關於單鏈表操做的,問到底有多少種解決方案,今天咱們就來聊聊。算法

題目的大體意思是:函數

假設存在一個無序單鏈表,將重複結點去除後,並保原順序。去重前:1→3→1→5→5→7去重後:1→3→5→7性能

順序刪除

經過雙重循環直接在鏈表上執行刪除操做。外層循環用一個指針從第一個結點開始遍歷整個鏈表,而後內層循環用另一個指針遍歷其他結點,將與外層循環遍歷到的指針所指結點的數據域相同的結點刪除,以下圖所示。spa

假設外層循環從outerCur開始遍歷,當內層循環指針innerCur遍歷到上圖實線所示的位置(outerCur.data==innerCur.data)時,此時須要把innerCur指向的結點刪除。3d

具體步驟以下:指針

  • 用tmp記錄待刪除的結點的地址。code

  • 爲了可以在刪除tmp結點後繼續遍歷鏈表中其他的結點,使innerCur指針指向它的後繼結點:innerCur=innerCur.nextblog

  • 從鏈表中刪除tmp結點。遞歸

實現代碼以下:性能分析

 

img

 

 

img

 

 

img

 

運行結果:

 

img

 

算法性能分析

因爲這種方法採用雙重循環對鏈表進行遍歷,所以,時間複雜度爲O(N^2)。其中,N爲鏈表的長度。在遍歷鏈表的過程當中,使用了常量個額外的指針變量來保存當前遍歷的結點、前驅結點和被刪除的結點,所以,空間複雜度爲O(1)

遞歸法

主要思路爲:對於結點cur,首先遞歸地刪除以cur.next爲首的子鏈表中重複的結點,接着從以cur.next爲首的子鏈表中找出與cur有着相同數據域的結點並刪除。

實現代碼以下:

 

img

 

 

img

 

 

img

 

算法性能分析

這種方法與方法一相似,從本質上而言,因爲這種方法須要對鏈表進行雙重遍歷,所以,時間複雜度爲O(N^2)。其中,N爲鏈表的長度。因爲遞歸法會增長許多額外的函數調用,所以,從理論上講,該方法效率比前面的方法低。

空間換時間

一般狀況下,爲了下降時間複雜度,每每在條件容許的狀況下,經過使用輔助空間實現。

具體而言,主要思路以下。

  • 創建一個HashSet,HashSet中的內容爲已經遍歷過的結點內容,並將其初始化爲空。

  • 從頭開始遍歷鏈表中的因此結點,存在如下兩種可能性:

  • 若是結點內容已經在HashSet中,則刪除此結點,繼續向後遍歷。

  • 若是結點內容不在HashSet中,則保留此結點,將此結點內容添加到HashSet中,繼續向後遍歷。

「引伸:如何從有序鏈表中移除重複項?」

如鏈表:1,三、五、五、七、七、八、9

去重後:1,三、五、七、八、9

分析與解答

上述介紹的方法也適用於鏈表有序的狀況,可是因爲以上方法沒有充分利用到鏈表有序這個條件,所以,算法的性能確定不是最優的。本題中,因爲鏈表具備有序性,所以,不須要對鏈表進行兩次遍歷。因此,有以下思路:用cur 指向鏈表第一個結點,此時須要分爲如下兩種狀況討論。

  • 若是cur.data==cur.next.data,那麼刪除cur.next結點。

  • 若是cur.data!=cur.next.data,那麼cur=cur.next,繼續遍歷其他結點。

總結

對於無序單鏈表中,想要刪除其中重複的結點(多個重複結點保留一個)。刪除辦法有按照順序刪除、使用遞歸方式刪除以及能夠使用空間換時間(HashSet中元素的惟一性)。

點贊越多,bug越少~

相關文章
相關標籤/搜索