1. 题目描述
在 O(n log n) 时间复杂度和常数级空间复杂度下,对链表进行排序。
示例 1:
输入: 4->2->1->3输出: 1->2->3->4
示例 2:
输入: -1->5->3->4->0输出: -1->0->3->4->5
2. 解题思路
(1)归并排序:
题目要求在O(n log n) 时间复杂度和常数级空间复杂度下对链表进行排序,恰好归并排序可以满足要求。
其主要思路如下:
- 先判断链表是否只有一个元素,若是则直接返回
- 使用快慢指针,找到链表的中间节点
- 对链表的前半部分和后半部分分别递归的进行归并排序
- 最后将两个子链表进行合并
(2)借助数组来实现:
我们可以借助数组来实现这个题目,将链表转化为数组,对数组的元素进行排序。排序完成之后,将数组再转化为链表。
不过这种方法空间复杂度为O(n)
3. 代码实现
归并排序:
/*** Definition for singly-linked list.* function ListNode(val) {* this.val = val;* this.next = null;* }*//*** @param {ListNode} head* @return {ListNode}*/var sortList = function(head) {// 若为空链表或只有一个节点,就直接返回if(head === null || head.next === null){return head}// 使用快慢指针获取链表的中间值let fast = headlet slow = headwhile(slow.next && fast.next && fast.next.next){slow = slow.nextfast = fast.next.next}// 将链表分成两个const middle = slow.nextslow.next = null// 对左右的两个链表分别递归的进行归并排序const left = headconst right = middlereturn merge(sortList(left), sortList(right))};function merge (left, right) {// 初始化一个空的结果节点let res = new ListNode(null);// 当前节点let prev = res;while (left && right) {// 如果左边的值小于右边的值,当前节点指向左节点,左节点指向下一个节点if (left.val < right.val) {[prev.next, left] = [left, left.next]}else {// 如果右边的值小于左边的值,当前节点指向右节点,右节点指向下一个节点[prev.next, right] = [right, right.next];}// 当前节点指向下一个节点prev = prev.next;}// 如果还有剩余的节点,就直接拼接在结果链表的最后prev.next = left ? left : right;return res.next;}
数组实现:
/*** Definition for singly-linked list.* function ListNode(val) {* this.val = val;* this.next = null;* }*//*** @param {ListNode} head* @return {ListNode}*/var sortList = function(head) {if(head === null || head.next === null){return head}let cur = headlet index = 0const arr = []// 将链表转化为数组while(cur){arr[index] = cur.valcur = cur.nextindex ++}// 对数组进行排序arr.sort((a,b) => a-b)// 将数组转化为链表cur = headindex = 0while(cur){cur.val = arr[index]index ++cur = cur.next}return head};
4. 提交结果
归并排序:
数组实现:
