奇偶鏈表問題
作者:Grey
原文地址:
題目描述
給定一個單鏈表,把所有的奇數節點和偶數節點分別排在一起。請注意,這裏的奇數節點和偶數節點指的是節點編號的奇偶性,而不是節點的值的奇偶性。
請嘗試使用原地算法完成。
你的算法的空間複雜度應爲 O(1),
時間複雜度應爲 O(nodes),nodes 爲節點總數。
示例 1:
輸入: 1->2->3->4->5->NULL
輸出: 1->3->5->2->4->NULL
示例 2:
輸入: 2->1->3->5->6->4->7->NULL
輸出: 2->3->6->7->1->5->4->NULL
說明: 應當保持奇數節點和偶數節點的相對順序。
鏈表的第一個節點視爲奇數節點,第二個節點視爲偶數節點,以此類推。
主要思路
如果用輔助數組來做,非常簡單,但是不滿足題目的要求,因爲題目要求空間複雜度 O(1),意味着不能額外申請輔助數組,換一個思路,考慮用一個整型變量來記錄遍歷的位置是奇數還是偶數,然後用四個指針分別記錄當前奇數鏈表的開頭,結尾;偶數鏈表的開頭和結尾,最後把兩個鏈表串聯起來即可,所以,只需要設置五個變量即可完成整個算法。
// 奇數鏈表的開頭節點
ListNode oddStart = null;
// 奇數鏈表的結尾節點
ListNode oddEnd = null;
// 偶數鏈表的開頭節點
ListNode evenStart = null;
// 偶數鏈表的結尾節點
ListNode evenEnd = null;
// 當前遍歷到的節點
ListNode cur = head;
// 當前遍歷到的位置,根據題目意思,從 1 開始
int count = 1;
整個流程如下,遍歷 cur 指針,同步記錄 count,如果 count 記錄的位置是奇數, 則構造奇數鏈表,如果 count 位置記錄的是偶數,則構造偶數鏈表。
構造的過程也比較簡單,以構造奇數鏈表爲例:
如果 oddStart
變量爲空,則說明奇數鏈表未初始化,則直接初始化
oddStart = cur;
oddEnd = cur;
奇數鏈表的頭尾指針都指向 cur,說明初始化完成;
否則,說明奇數鏈表已經初始化過,則把奇數鏈表的尾部的 next 直接連上 cur
,然後把奇數鏈表的尾部指針指向 cur
,即
oddEnd.next = cur;
oddEnd = cur;
構造偶數鏈表的過程和構造奇數鏈表的過程同理,不贅述。
構造好兩個鏈表以後,把兩個鏈表連接起來即可,連接的邏輯如下:
如果偶數鏈表尾部不爲空,則奇數鏈表一定不爲空,且偶數鏈表的尾部就是變換後鏈表的尾部,即
if (evenEnd != null) {
evenEnd.next = null;
}
最後,要把奇數鏈表尾部的 next 連接上偶數鏈表的頭部
oddEnd.next = evenStart;
完整代碼如下
class Solution {
// 奇數節點和偶數節點放在一起
// 所有偶數下標的數一定要在奇數下標數之後(注意:是下標而非值)
public static ListNode oddEvenList(ListNode head) {
if (head == null || head.next == null || head.next.next == null) {
return head;
}
ListNode oddStart = null;
ListNode oddEnd = null;
ListNode evenStart = null;
ListNode evenEnd = null;
ListNode cur = head;
int count = 1;
while (cur != null) {
if ((count & 1) == 1) {
// 奇數
if (oddStart == null) {
oddStart = cur;
} else {
oddEnd.next = cur;
}
oddEnd = cur;
} else {
// 偶數
if (evenStart == null) {
evenStart = cur;
} else {
evenEnd.next = cur;
}
evenEnd = cur;
}
count++;
cur = cur.next;
}
if (evenEnd != null) {
evenEnd.next = null;
}
oddEnd.next = evenStart;
return oddStart;
}
}