leetcode每日一道(7):搞懂鏈表複雜重排序問題(快慢指針、鏈表翻轉、鏈表合併)

題目

將給定的單鏈表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}.

思路分析

不知大家看懂了題目了嗎,相當於是一個鏈表中,首尾各取一個組成新的鏈表,不斷重複直到整個鏈表的元素遍歷完成。
本題的思路是這樣的:

  1. 用快慢指針找到鏈表中點,然後分成兩條鏈;
  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;
		}

	}

};
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章