LeetCode Notes_#24_兩兩交換連結串列中的節點
阿新 • • 發佈:2020-11-04
LeetCode Notes_#24_兩兩交換連結串列中的節點
LeetCodeContents
題目
解答
方法1:迭代+修改指標
一開始自己寫,發現有兩個難點不好解決:
- 最後無法得到修改後連結串列的頭節點
- 第一組的兩個節點沒法連線到第二組的兩個節點,舉例來說就是1沒法連線到4
問題在於:
- 頭節點需要通過啞節點
dummyHead.next
來獲取,沒有啞節點的話,是沒法處理這個問題的 - 每次迭代開始的位置應該是“上一組的兩個節點的尾巴”,舉例來說,第二輪迭代時,
cur
具體來說,我們需要維護3個指標,第一個指標指向的是“上一組的兩個節點的尾巴”,後兩個指標則指向下一組節點的兩個節點。這樣就比較方便進行各種指標的修改。
class Solution {
public ListNode swapPairs(ListNode head) {
ListNode dummyHead = new ListNode(0);
dummyHead.next = head;
ListNode cur = dummyHead;
while(cur.next != null && cur.next.next != null){
ListNode node1 = cur.next;
ListNode node2 = cur.next.next;
node1.next = node2.next;
cur.next = node2;
node2.next = node1;
cur = cur.next.next;
}
return dummyHead.next;
}
}
複雜度分析
時間複雜度:O(n)
空間複雜度:O(1)
方法2:迭代+棧
我們還可以利用棧的性質,將原始連結串列節點入棧,然後將出棧的節點加入新的連結串列,以達到反轉的目的。這樣的方法直接避免了複雜的指標操作,程式碼看起來非常清晰,其實執行效率並不比方法1要低。
class Solution {
public ListNode swapPairs(ListNode head) {
//注意:這種方法並不是在原地進行修改,而是建立一條新連結串列,新連結串列的啞頭節點是newListDummy
ListNode newListDummy = new ListNode(0);
Deque<ListNode> stack = new LinkedList<>();
ListNode newListPtr = newListDummy;
ListNode oldListPtr = head;
while(oldListPtr != null && oldListPtr.next != null){
//將原始連結串列上的節點入棧
stack.addLast(oldListPtr);
stack.addLast(oldListPtr.next);
oldListPtr = oldListPtr.next.next;
//將剛才加入的兩個節點出棧,連線到新連結串列之後
newListPtr.next = stack.removeLast();
newListPtr.next.next = stack.removeLast();
newListPtr = newListPtr.next.next;
}
//因為迴圈結束,證明oldListPtr和oldListPtr.next不會同時非null
//只有兩個可能,第一種是:oldListPtr非null,而ololdListPtr.next是null(對應於奇數個節點的情況)
if(oldListPtr != null){
newListPtr.next = oldListPtr;
}
//第二種是:oldListPtr和ololdListPtr.next都是null(對應於偶數個節點的情況)
else{
//如果沒有這一句,會導致連結串列中出現環,無法通過
newListPtr.next = null;
}
return newListDummy.next;
}
}
複雜度分析
時間複雜度:O(n)
空間複雜度:O(n)
,建立了一條新的連結串列
方法3:遞迴
看到一個很好的圖解,轉載自三道題套路解決遞迴問題 | lyl's blog
這個寫法看起來有點難懂...感覺我自己是根本不會想到這種方法的。
class Solution {
public ListNode swapPairs(ListNode head) {
//遞迴終止條件:連結串列只剩一個節點,或者沒有節點了,就沒得交換了,返回已經處理好的連結串列
if(head == null || head.next == null){
return head;
}
//僅僅是暫存一下head.next,因為接下來head.next要改變了
ListNode next = head.next;
//遞迴呼叫,傳入的引數是下下個節點,也就是說,從下一組開始翻轉
head.next = swapPairs(next.next);
//這一句和上一句不能交換位置,因為交換過後next就先改變了
next.next = head;
return next;
}
}
複雜度分析
時間複雜度:O(n)
空間複雜度:O(n)
,遞迴棧空間