一、題目
樂扣原題:https://leetcode-cn.com/problems/sort-list/submissions/
二、轉化爲數組
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) { val = x; }
* }
*/
class Solution {
public ListNode sortList(ListNode head) {
if (null == head) {
return null;
}
// 將鏈表轉化爲數組
List<Integer> list = new ArrayList<>();
while (null != head) {
list.add(head.val);
head = head.next;
}
// 數組遞增排序
Collections.sort(list);
// 構造結果鏈表
ListNode root = new ListNode(-1);
ListNode cur = root;
for (Integer val : list) {
cur.next = new ListNode(val);
cur = cur.next;
}
return root.next;
}
}
- 基本思路:單向鏈表相比數組,隨機訪問的難度大,因此可以考慮轉化爲數組問題解決;
- 時間複雜度:O(nlog(n))。鏈表遍歷O(n),數組排序O(nlog(n)),結果構造O(n);
- 空間複雜度:O(n)。存儲鏈表元素的列表O(n),構造新的鏈表O(n);
三、歸併排序
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) { val = x; }
* }
*/
class Solution {
public ListNode sortList(ListNode head) {
if (null == head) {
return null;
}
return split(head);
}
private ListNode split(ListNode node) {
// 遞歸分解到null或單節點時,直接返回
if (null == node || null == node.next) {
return node;
}
// 通過快慢指針,標記鏈表的中間節點
ListNode slow = node;
ListNode fast = node.next;
while (null != fast && null != fast.next) {
slow = slow.next;
fast = fast.next.next;
}
// 以中間節點將鏈表一分爲二,通過slow.next = null斷鏈
ListNode pre = node;
ListNode post = slow.next;
slow.next = null;
// 遞歸分解兩段鏈表,直至不可再分(null/單節點)
ListNode left = split(pre);
ListNode right = split(post);
// 返回兩兩歸併結果
return merge(left, right);
}
private ListNode merge(ListNode left, ListNode right) {
ListNode subResult = new ListNode(-1);
ListNode cur = subResult;
while (null != left && null != right) {
if (left.val <= right.val) {
cur.next = new ListNode(left.val);
left = left.next;
} else {
cur.next = new ListNode(right.val);
right = right.next;
}
cur = cur.next;
}
if (null != left) {
cur.next = left;
}
if (null != right) {
cur.next = right;
}
return subResult.next;
}
}
- 基本思路:根據題目要求的O(nlog(n))時間複雜度,以及單向鏈表的特性,可以聯想到歸併排序;
- 時間複雜度:O(nlog(n))。歸併排序的時間複雜度穩定爲O(nlog(n));
- 空間複雜度:O(log(n))。體現爲遞歸過程中的棧空間消耗,即二叉樹的最小深度,空間複雜度爲O(log(n));
四、總結
- 在單向鏈表中,經常會使用到快慢指針尋找鏈表的中點;