題目描述
給定一個單鏈表,把所有的奇數節點和偶數節點分別排在一起。請注意,這裏的奇數節點和偶數節點指的是節點編號的奇偶性,而不是節點的值的奇偶性。
請嘗試使用原地算法完成。你的算法的空間複雜度應爲O(1)
,時間複雜度應爲O(nodes)
,nodes
爲節點總數。
示例1:
輸入: head = [1, 2, 3, 4, 5]
輸出: [1, 3, 5, 2, 4]
示例2:
輸入: head = [2, 1, 3, 5, 6, 4, 7]
輸出: [2, 3, 6, 7, 1, 5, 4]
說明:
- 應保持奇數節點和偶數節點的相對順序;
- 鏈表的第一個節點視爲奇數節點,第二個節點視爲偶數節點,以此類推;
思路分析
我們通過簡單的思考,可以想出通過對鏈表進行“奇數分區”和“偶數分區”進行節點區分,此時我們不免會想到,奇數分區需要一個指針指向奇數分區尾節點oddTail
以便後續節點的插入;同樣地, 偶數分區也需要一個指針指向偶數分區尾節點evenTail
;同時,我們遍歷還需要一個遍歷指針p
。
此時我們對遍歷、插入的準備工作進行了簡單討論,這裏我們通過代碼實現時,會發現我們需要對p
遍歷時對節點的 “奇偶性”進行判斷 ,因爲這裏是下標的奇偶性,故我們可以通過設置一個布爾常量來進行標識。
再進一步思考,因爲鏈表之被分爲兩個分區,在代碼運行過程中鏈表一般可被表示爲三個區域:a. 偶數分區;b. 奇數分區;c. 待遍歷分區。如圖1所示:
圖1
這裏我們可以看到,在p
遍歷的時候,會已知保持與指針evenTail
的前後關係,則我們這裏去掉p
指針,則現在我們需要的就是兩個分區指針oddTail, evenTail
和一個布爾變量進行功能實現。這裏我們直接給出解題步驟與解題代碼:
解題步驟
- 初始化兩個分區指針
oddTail, evenTail
和布爾變量isOddNode
; - 遍歷原始鏈表,根據
isOddNode
判斷evenTail.next
是否插入奇數分區; - 當
evenTail.next == null
時停止並返回head
.
解題代碼
public static ListNode solution(ListNode head) {
if (head == null || head.next == null || head.next.next == null) {
return head;
}
/* Step1: Init. pointers */
ListNode oddTail = head;
ListNode evenTail = head.next;
boolean isOddNode = true;
/* Step2: go through the head-list
and
split nodes according the odevity(奇偶性) of index
*/
while(evenTail.next != null){
ListNode node = evenTail.next;
// oddNode: directly insert after oddTail
if(isOddNode){
evenTail.next = evenTail.next.next;
node.next = oddTail.next;
oddTail.next = node;
oddTail = node;
isOddNode = false;
}else{ // evenNode: just move forward
evenTail = evenTail.next;
isOddNode = true;
}
}
/* Step3: return head */
return head;
}
複雜度分析
時間複雜度:我們對原始鏈表進行了一次遍歷,容易理解時間複雜度爲O(N)
;
空間複雜度:我們這裏沒有設置輔助容器,只需要兩個指針和一個布爾量,故空間複雜度爲O(1)
.
GitHub源碼
完整可運行文件請訪問GitHub。