LinkedList专题2
203 Remove Linked List Elements
思路:考慮1 : 可能有多個節點符合;考慮2:命中節點是head;考慮3:命中節點是尾節點;考慮4:命中節點是中間的普通節點。
學習1:在linkedList 運用遞歸的思路還是很常見的,我還沒有形成習慣。不斷縮小問題規模。
學習2:因為第一版有head節點的特殊處理,可以采取的措施是:加一個假的head或者是dummy節點。代碼漂亮多了。
public ListNode removeElementsV3(ListNode head, int val) {ListNode dummy = new ListNode(-1);dummy .next = head;ListNode node = head;ListNode preNode = dummy ;while(node!=null){if(node.val==val){preNode.next = node.next;}else{preNode = node;}node = node.next;}return dummy .next;}代碼
160 Intersection of Two Linked Lists
思路:兩個鏈表相交的起點。方法一:暴力搜索。listA的每個節點與listB的每個節點比較。時間復雜度O(m*n)。方法二:將listA的每個節點放入map中,遍歷listB的每個節點與map比較。時間復雜度O(n),空間復雜度O(n)。這兩個都不符合要求。
學習:難點是能夠觀察到:如果listA和listB有交集,那么從交集點開始之后所有的node是相等的,那么長度也是相同的。所以如果有長度差異,一定是在列表的前端。正如demo中所示。可以分別計算兩個列表的長度lenA,lenB。長的列表先移動|lenA-lenB|步;之后兩個指針一起移動直到所指節點相同。
代碼
19 Remove Nth Node From End of List
思路:從尾部開始計算,刪除第n個節點。
如果是從頭部開始計算,刪除第n個節點就比較好處理了。那就把問題轉換一下。從尾部開始的第n個節點=從頭部開始的第幾個節點。
經過畫圖舉例知道 應該是從頭部開始第(len-n+1)節點,len是list長度。
假設要刪除的節點nodeA ,應該是nodeA的上一個節點.next = nodeA.next。需要處理nodeA的上一個節點不存在的情況,這里加入一個dummy節點。
思路2:使用兩個指針first、second。first先走n+1個節點(因為有dummy節點),然后second再走。當first到達隊尾的時候,second距離隊尾還有n個節點。
學習網頁
代碼
23 Merge k Sorted Lists
合并k個已經排序好的列表。這個題目有多種解決思路。參考文章。
思路1:把所有數據放在一個List,然后排序list。最后再創建ListNode。時間復雜度O(NlogN)O(NlogN),N是所有節點的總數。所有數據放入List需要O(n);排序需要O(NlogN)O(NlogN),創建節點需要O(N)。空間復雜度O(N)。
思路2:每次比較k個頭節點,選擇最小的節點。然后繼續比較頭節點。時間復雜度:O(kN)。k是數組長度,N是節點總數。每次比較需要比較k-1次,有N次比較。
思路3:對思路2的改進。每次把頭結點的值放入優先隊列中,取得最小值。時間復雜度:(O(Nlogk))(O(Nlogk))。插入和彈出優先隊列需要耗時O(logk)O(logk),獲得最小值耗時O(1)。
思路4:把k個隊列合并問題轉為2個隊列合并問題。可以第0個和第1個合并得到result;result再繼續和第2個、第3個隊列合并。時間復雜度:O(kN)O(kN)。N是兩個list的長度。k個隊列需要合并k-1次。
思路5:對思路4的改進。使用分治法(Divide and conquer)。合并0,1隊列得到0隊列;合并2,3隊列得到2隊列….;第二層 合并0,2隊列得到0隊列,合并4,6隊列得到4隊列;第三層合并0,4隊列得到0隊列…..一直到結束。時間復雜度:O(Nlogk)O(Nlogk)。N是兩個隊列的節點總數。因為會合并logk次。
代碼
25 Reverse Nodes in k-Group
思路:將整個列表分成幾個長度為k的子鏈表;對每一個子鏈表反轉。長度不為k的子鏈表保持不動。
思路1:找到每一個子鏈表開始、結束下標,然后調用 92 Reverse Linked List II 。
這樣會有一些重復的跳過m個節點的操作。可以進一步優化。從head開始數,數夠了k步就從head開始反轉長度為k的子鏈表;接著再從當前節點開始數。夠k個就反轉。不夠就退出。
學習:自己反轉的代碼寫的有點凌亂。再次學習了遞歸思想。
如果要反轉鏈表1->2->3->4->5中1到3的部分得到:3->2->1->4->5。左側從左向右是一種思路,右側從右向左也是一種方法。
代碼
61 Rotate List
思路:因為k可能大于len(鏈表長度)。所以1 計算列表長度;2 k=k % len;3 將指針移動到len-k的位置,這個位置是開始rotate節點的上一個節點。4 反轉。
代碼
82 Remove Duplicates from Sorted List II
思路:留下鏈表中沒有重復出現的元素。比較簡單。直觀地解決就可以。
代碼
86 Partition List
思路:用兩個指針smallHead,biggerHead分別指向小于x的節點列表和大于等于x的節點列表。最后將兩個列表合并返回。
代碼
143 Reorder List
思路:1 找到一半節點;2 反轉第二部分鏈表;3合并兩個鏈表。重要的是代碼怎么寫。
代碼
147 Insertion Sort List
思路:處理位置i,從0到i-1是已經排序好的。我寫代碼的時候還是受數組排序的思維影響比較重。在學習代碼中,別人把排序好的作為一個list處理。相對來說要比較好。
代碼
總結
以上是生活随笔為你收集整理的LinkedList专题2的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 代码走查和代码审查_代码审查是个好主意的
- 下一篇: 使用 python 操作 redis