[LeetCode] Sort List

Sort a linked list in O(n log n) time using constant space complexity.

這題思路比較直接。按照題目要求,需要在O(N*logN)時間內完成排序,所以可以考慮的排序方法只有三個:快速排序、歸併排序和堆排序。然而,快速排序要求能在常數時間內置換兩個指定元素,所以需要支持O(1)時間內的隨機訪問,這個無法在鏈表上實現,所以可以排除快速排序。此外,堆排序需要O(N)的額外空間進行堆的建立,而題目要求常數的空間複雜度,所以也可以排除。如此一來,只有歸併排序可以考慮了。

按照分治法原理,其實也就只用實現兩個步驟,即拆分鏈表和合並鏈表,都可以通過鏈表實現。把一個鏈表拆分成兩半,簡單做法就是先掃描一遍獲得鏈表長度,然後再掃描一半長度進行拆分。這樣需要兩次掃描,雖然時間複雜度一樣。更有效的方法是使用2個快慢指針,當快指針走到頭的時候,慢指針會到達第一個的子鏈表的尾部。合併鏈表很直接,因爲無論是用數組還是鏈表,都只用順序掃描兩個序列。

	// merge the two sorted sublists
	private ListNode merge(ListNode head1, ListNode head2) {
		if (head1 == null) {
			return head2;
		} else if (head2 == null) {
			return head1;
		}

		ListNode head, prev;
		if (head1.val < head2.val) {
			head = head1;
			head1 = head1.next;
		} else {
			head = head2;
			head2 = head2.next;
		}
		prev = head;

		while (head1 != null && head2 != null) {
			if (head1.val < head2.val) {
				prev.next = head1;
				head1 = head1.next;
			} else {
				prev.next = head2;
				head2 = head2.next;
			}
			prev = prev.next;
		}

		if (head1 != null) {
			prev.next = head1;
		} else if (head2 != null) {
			prev.next = head2;
		}

		return head;
	}

	public ListNode sortList(ListNode head) {
		ListNode head1, head2; // sublist heads

		// split the list into two sublists
		if (head == null || head.next == null) {
			return head;
		} else {
			ListNode fastNode = head.next, slowNode = head;
			while (fastNode != null) {
				fastNode = fastNode.next;
				if (fastNode != null) {
					fastNode = fastNode.next;
					slowNode = slowNode.next;
				}
			}

			head1 = head;
			head2 = slowNode.next;
			slowNode.next = null;
		}

		// sort the two sublists recursively
		head1 = sortList(head1);
		head2 = sortList(head2);

		return merge(head1, head2);
	}

其實我本來想把拆分鏈表這一步也用一個函數封裝的,不過這樣的話要求對兩個子鏈表的表頭地址傳引用,在Java裏不好實現,不過可以在C++代碼裏引入二級指針或者對節點地址傳引用實現。
發佈了60 篇原創文章 · 獲贊 8 · 訪問量 24萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章