1. 程式人生 > >演算法修煉之路——【連結串列】Leetcode24 兩兩交換連結串列中的節點

演算法修煉之路——【連結串列】Leetcode24 兩兩交換連結串列中的節點

題目描述

給定一單鏈表,兩兩交換其中相鄰的節點,並返回交換後的連結串列。

你不能只是簡單的改變節點內部的值,而是需要實際的進行節點交換。

示例:

輸入:head = [1, 2, 3, 4]

輸出:head = [2, 1, 4, 3]

解題思路

我們通過示例可以簡單瞭解到,需要兩兩進行位置互換,但是互換的動作需要涉及到前置節點與後置節點。這裡為方便理解,我們先單獨給出四個節點:

 

 圖1

 

見圖1所示,我們在T1時刻交換[1, 2]兩個節點,T2時刻交換[3, 4]。

這裡易看出,此問題可以解為:

  1. 兩兩交換
  2. 迭代兩兩交換

對於問題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. 初始化兩個指標,一左一右;且為統一規則,採取哨兵機制;
  2. 迭代:節點交換,並更新下一對節點的靠前前置節點;
  3. 迭代終止條件為兩指標均不為空;終止後返回哨兵節點的下一節點。

解題程式碼

 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