[LeetCode] 148. Sort List(单链表排序)
-
Difficulty: Medium
-
Related Topics: Linked List, Sort
Description
Given the head
of a linked list, return the list after sorting it in ascending order.
给定单链表的头节点 head
,对其升序排序,然后返回该链表。
Follow up
Can you sort the linked list in O(n logn)
time and O(1)
memory (i.e. constant space)?
你能以 \(O(N\log{N})\) 的时间复杂度和 \(O(1)\) 的空间复杂度解决它吗?
Examples
Example 1
Input: head = [4,2,1,3]
Output: [1,2,3,4]
Example 2
Input: head = [-1,5,3,4,0]
Output: [-1,0,3,4,5]
Example 3
Input: head = []
Output: []
Constraints
- The number of nodes in the list is in the range
[0, 5 * 104]
. -105 <= Node.val <= 105
Solution
对于单链表来说最合适的排序算法,\(O(N^2)\) 算法里比较适合的是插入排序,\(O(N\log{N})\) 算法里比较适合的是归并排序,本题将他们各自实现一遍,详细的步骤附在代码的注释里。
插入排序版本:
/**
* Example:
* var li = ListNode(5)
* var v = li.`val`
* Definition for singly-linked list.
* class ListNode(var `val`: Int) {
* var next: ListNode? = null
* }
*/
class Solution {
fun sortList(head: ListNode?): ListNode? {
// 链表为空或只有一个元素,就不管它了,直接返回
if (head?.next == null) {
return head
}
// 在这里,交换是交换节点本身,所以加入 dummy 节点
val dummy = ListNode(-1)
dummy.next = head
// end 初始为 head,在排序过程中,dummy(不包括,仅为了方便交换) 到 head(包括)之间的所有节点都是有序的
// 我们要做的,就是把 head 后面的节点不断插入这个有序的区间里。
var end = head
// cur -> 当前要处理的节点
var cur = head.next
while (cur != null) {
var p = dummy.next
var pre: ListNode? = dummy
// 找到合适的插入位置
while (p != cur && cur.`val` >= p!!.`val`) {
p = p.next
pre = pre?.next
}
if (cur === p) {
// 当前节点是已排序区间内最大的,直接把区间后移
end = cur
} else {
// 插入进合适的位置
end?.next = cur.next
cur.next = p
pre?.next = cur
}
// 处理下一个节点
cur = end?.next
}
return dummy.next
}
}
归并排序版:
/**
* Example:
* var li = ListNode(5)
* var v = li.`val`
* Definition for singly-linked list.
* class ListNode(var `val`: Int) {
* var next: ListNode? = null
* }
*/
class Solution {
fun sortList(head: ListNode?): ListNode? {
// 如果链表为空或者只有一个节点,不管它了,直接返回
if (head?.next == null) {
return head
}
// 双指针法找出中间节点
var fast = head
var slow = head
while (fast?.next?.next != null) {
fast = fast.next?.next
slow = slow?.next
}
// 将链表的前后两部分断开
fast = slow
slow = slow?.next
fast?.next = null
// 分别对前后两段进行排序
fast = sortList(head)
slow = sortList(slow)
return merge(fast, slow)
}
private fun merge(left: ListNode?, right: ListNode?): ListNode? {
// 特殊情况处理,一边为空就返回另一边
if (left == null) {
return right
}
if (right == null) {
return left
}
var p = left
var q = right
val dummy = ListNode(-1)
var result: ListNode? = dummy
while (p != null && q != null) {
if (p.`val` < q.`val`) {
result?.next = p
p = p.next
} else {
result?.next = q
q = q.next
}
result = result?.next
}
result?.next = p?:q
return dummy.next
}
}