資料結構與演算法(連結串列)
資料結構與演算法(連結串列)
1,連結串列的資料結構
(1)基本實現(組成):由一個一個結點構成。
自己動手實現:定義了一個含有資料域 和 指標的 結點類。
(2)連結串列主要的功能(增刪改查):定義一些介面方法
(3)過程中進行重構連結串列,將 增刪改查 或者一些通用的介面或者屬性封裝到外部抽象類或者介面(方便設計給其他類用這樣子):
(整個版本一的連結串列過程如此)
過程中增刪改查實現的具體程式碼就 略。。。
增加:可以在任意一個位置進行增加結點
刪除:可以在任意一個位置進行刪除結點
修改:可以在任意一個位置進行修改結點
查詢:可以查詢任意一個位置的結點
✿ 升級版本
① 擁有虛擬頭結點的連結串列(統一了增加、刪除時接口裡的一些條件的判斷)
② 雙端(雙指標)連結串列(加快了查詢某個位置的結點~ 之前只能從頭到尾的遍歷,現在多了一個指標,便可以從尾到頭遍歷啦)
~~JDK1.8中的LinkedList中就是雙向連結串列(從原始碼分析得知的)
③ 迴圈連結串列(讓最後一個結點的指標指向了第一個結點)
④ 雙端迴圈連結串列(有兩個指標+ (最後一個結點的指標last 指向了第一個結點 、第一個結點的prev 指標指向最後一個結點))
2,連結串列的力扣演算法題:
總結一些小套路吧 (沒有通用的套路,就講一下方法哈):
✿ 自己需要先知道的是連結串列的特點就是一個一個結點構成(一般沒有特別強調的連結串列都是普通的連結串列(只有一個next 指標):找結點都是隻能從頭到尾去遍歷找它)
(1)138_複製帶隨機指標的連結串列 的方法 :
方法一:使用遞迴+ hashMap (因為隨機指標:一個節點可能被多個其他節點指向)
/** hashMpa 避免重複建立 **/
當我們拷貝節點時,「當前節點的隨機指標指向的節點」可能還沒建立,因此我們需要變換思路。一個可行方案是,我們利用回溯的方式,讓每個節點的拷貝操作相互獨立。
方法二:間隔插秧法啦(把秧苗插進來後,以前是走一步,現在多了一個結點要多走一步)
* 第一步:插入苗
* 第二步:先處理隨機指標的複製(原本有隨機、next的複製都需要處理?):優先處理隨機(之所以要把苗插入,就是為了實現在同一流水線具有同一規則,如果先處理next 導致已經變成兩條連結串列了,拿不到隨機了)
(2)141_環形連結串列 的方法與套路 :
方法一:使用 HashSet 實現不重複的新增 【Set 集合特點:不重複】
// HashSet 底層是HashMap(新增元素時會判斷是否已經存在,已經存在會新增不成功)
if (!visited.add(head)) {
return true;
}
套路一:快慢指標法 (生活常識:操場跑圈,跑得快的最終會追上跑得慢的)
(3)142_環形連結串列II 的方法與套路 :
方法一:【Set 集合特點:不重複】,通過 contains() 方法進行判斷
套路一:快慢指標法 [ 追上之後,通過將特殊位置點(起點、 交點、相遇點)~ 快慢指標之間的位移差距是兩倍--> 推匯出起點到交點 = 相遇點到交點]
(4)160_相交連結串列 的方法與套路 :
方法一:Set集合(裝入一條連結串列,然後以它為標準,依次拿另外一條連結串列的每個結點與它對比)
套路一:處理一下長度,使得兩條連結串列的長度相同後進行同步運動(相遇了即是交點)
(5)19_刪除連結串列的倒數第N個結點 的方法與套路 :
方法一:通過求總長len - N + 1 得到需要刪除連結串列的前一個結點
套路一:倒序~聯絡到棧(後進先出~倒序思維):通過棧(後進先出(pop掉 後面 第N個,從而可以拿到待刪除結點的前一個結點))
套路二:本質上是將倒數轉化成(兩個點之間)具體的距離,通過設定兩個距離是n 的指標(不斷的往後走,走到最後,差距便是倒數)~ 資料-->距離
(6)2_兩數相加 的套路 :
套路一 :官網用 || 把連結串列是否為空的所有情況都考慮(加上利用題意:將空鏈的資料初始為 0, 過程是將兩條鏈的資料進行相加)
套路框架:
while (l1 != null || l2 != null){ if (l1 != null) { l1 = l1.next; } if (l2 != null) { l2 = l2.next; } } |
(7)203_移除連結串列元素 的方法和套路 :
方法一:遞迴,在從第二個結點開始進行移除,最後考慮上第一個結點的情況
套路一:加上了一個虛擬頭結點後,拿自身結點的next 去 比較,一旦next 是待刪除目標結點,則自身便是那個待刪除結點的前一個結點
(8)206_反轉連結串列 的方法 :
方法一:遞迴
方法二:頭插法
(9)21_合併兩個有序連結串列 的方法 和 套路 :
方法一:遞迴(將第一條連結串列從第二個結點開始與 第二條連結串列進行比較,然後再處理第一條連結串列剩下的第一個結點的情況)
套路一:兩條鏈同時進行比較大小, 當其中一條連結串列資料到達了null,再處理剩下另外一條連結串列的資料
套路二:(6)官網用 || 把連結串列是否為空的所有情況都考慮(加上利用題意:將空鏈的資料初始為 0 )
(10)23_合併K個升序連結串列 的方法 和 套路:
方法一:暴力法(一條一條新增進來的合併法)
套路一:分治合併法 (將 k 條不斷地進行劃分成兩部分,直到 部分中的連結串列數量為 1,開始二合一)
套路二:優先佇列法(就是小根堆(具體程式碼就是 PriorityQueue類(長度,比較器))~從小到大排序:
每條連結串列會依據連結串列頭的大小順序進行排序~ 連結串列頭小的放入前面,大的放到後面(從小到大~ 內部自動排序哈哈哈)),
每次都彈出連結串列頭最小的連結串列(然後取走連結串列頭,又放回剩餘的連結串列(讓它根據剩餘連結串列的頭在queue 中進行排序))。
(11)24_兩兩交換連結串列中的節點 的方法 和 套路: