演算法修煉之路——【連結串列】Leetcode24 兩兩交換連結串列中的節點
阿新 • • 發佈:2020-04-04
題目描述
給定一單鏈表,兩兩交換其中相鄰的節點,並返回交換後的連結串列。
你不能只是簡單的改變節點內部的值,而是需要實際的進行節點交換。
示例:
輸入:head = [1, 2, 3, 4]
輸出:head = [2, 1, 4, 3]
解題思路
我們通過示例可以簡單瞭解到,需要兩兩進行位置互換,但是互換的動作需要涉及到前置節點與後置節點。這裡為方便理解,我們先單獨給出四個節點:
圖1
見圖1所示,我們在T1時刻交換[1, 2]兩個節點,T2時刻交換[3, 4]。
這裡易看出,此問題可以解為:
- 兩兩交換
- 迭代兩兩交換
對於問題1:
我們將總體連結串列的兩兩交換位置分別為若干相同的問題1,解法則有:
1 /* 2 head = [1, 2, 3, 4] 3 first, focus [1, 2] 4 */ 5 ListNode currHead; // and currHead.next = left 6 7 leftP.next = rightP.next; // 1->2->3 changed to 1->3 8 right.next = leftP; // 1->3 changed to 2->1->3 9 currHead.next = rightP; //upgrate head of piece of this pair
這裡涉及到的額外節點資訊是兩個節點組的前置節點,即currHead;當我們交換[3, 4]時則有:
1 /* 2 head = [2, 1, 3, 4] 3 secod, focus [3, 4] 4 5 leftP point to 3, rightP 4. 6 */ 7 // currHead.next = leftP, here, currHead = ListNode(1) 8 9 // exchange node 3 and 4 10 leftP.next = rightP.next; 11 rightP.next = leftP; 12 currHead.next = rightP;
對於問題2:
截止到這裡,我們已經探索到了問題1的解法,接下來需要做的就是將填補問題1間的縫隙,即將他們融合為一個整體,這裡我們容易理解,在交換[3, 4]的時候,需要用到交換[1,2]後的靠後節點(這裡為ListNode(1)),則可以理解我們在兩兩交換時,統一的需要用到currHead, 即兩個節點[a, b]中 靠前節點a的前置節點,並需要在[a, b]交換位置後為下一對即將交換的節點更新它們所需的currHead。則我們可以將前兩部分程式碼融合為:
1 ListNode leftP = head; 2 ListNode rightP = head.next; 3 4 ListNode currHead = dummyHead; //for head node 5 6 7 // iteration 8 leftP.next = rightP.next; 9 rightP.next = leftP; 10 currHead.next = rightP; 11 12 //update pos of currHead 13 currHead = leftP;
步驟羅列
我們已經對問題的解答有了核心的理解,這裡將步驟進行進一步梳理:
- 初始化兩個指標,一左一右;且為統一規則,採取哨兵機制;
- 迭代:節點交換,並更新下一對節點的靠前前置節點;
- 迭代終止條件為兩指標均不為空;終止後返回哨兵節點的下一節點。
解題程式碼
1 public static ListNode solutionWithTwoP(ListNode head) { 2 if (head == null || head.next == null) { 3 return head; 4 } 5 6 //1. init pointers and dummyHead 7 ListNode dummyHead = new ListNode(-1); 8 dummyHead.next = head; 9 ListNode leftP = head; 10 ListNode rightP = head.next; 11 12 ListNode currHead = dummyHead; 13 14 //2. iteration 15 while (leftP != null && rightP != null) { 16 // exchange 17 leftP.next = rightP.next; 18 rightP.next = leftP; 19 currHead.next = rightP; 20 21 //update pos of currHead 22 currHead = leftP; 23 24 //move forward 25 leftP = leftP.next; 26 rightP = leftP == null? null : leftP.next; //attention here 27 } 28 29 return dummyHead.next; 30 }View Code
複雜度分析
時間複雜度:我們對資料僅進行了一次遍歷,所以時間複雜度為O(N);
空間複雜度:我們沒有藉助額外的容器,所以空間複雜度為常量級O(1)。
GitHub原始碼
完整可執行檔案請訪問GitHub。
&n