題目
將給定的單鏈表L: L 0→L 1→…→L n-1→L n,
重新排序爲: L 0→L n →L 1→L n-1→L 2→L n-2→…
要求使用原地算法,並且不改變節點的值
例如:
對於給定的單鏈表{1,2,3,4},將其重新排序爲{1,4,2,3}.
思路分析
不知大家看懂了題目了嗎,相當於是一個鏈表中,首尾各取一個組成新的鏈表,不斷重複直到整個鏈表的元素遍歷完成。
本題的思路是這樣的:
- 用快慢指針找到鏈表中點,然後分成兩條鏈;
- 對後面的鏈表進行翻轉;
- 將兩個鏈表進行融合;
可以看出,這道題涉及到快慢指針、翻轉鏈表、融合鏈表等多種知識,因此只要這道題搞清楚,相當於幾個知識點都弄清楚了。
但是在運行的過程中遇到一點問題,就是如果用調用函數的方法就是通不過,但是直接寫在函數中,就可以通過。看來這道題的要求還是蠻苛刻的?不過重要的是思路!
總的來說,收穫最大的就是,各個邊界的條件要想清楚,要考慮全面,最後簡化下來的代碼倒是很簡單。這就是代碼之美!
代碼
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
void reorderList(ListNode *head) {
if (!head || !head->next || !head->next->next)
return;
auto fast = head, slow = head;
while (fast->next && fast->next->next) {
fast = fast->next->next;
slow = slow->next;
}
auto second = slow->next;
slow->next = nullptr;
// 這裏翻轉
auto p = second;
auto q = second->next;
while (q) {
//auto next = cur->next;
p->next = q->next; //這裏的思路是十分巧妙的,相當於是p的位置是沒有變的,
//一直是指向頭部。
q->next = second;
second = q;
q = p->next; //因爲p->next保存了下一個節點,以防止斷鏈。
//second最後就是我們要的頭結點,q最後就變成了空節點
}
//開始merge,merge的過程,也要考慮保存後面的節點的問題,然後想清楚是怎樣的循環過程。
p = head;
q = second;
while (q) {
head = p->next;
second = q->next;
p->next = q;
q->next = head;
p = head;
q = second;
}
}
};