一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第9天,点击查看活动详情。
一.题目:
148. 排序链表 给你链表的头结点
head,请将其按 升序 排列并返回 排序后的链表 。 示例 1:
输入: head = [4,2,1,3]
输出: [1,2,3,4]
示例 2:
输入: head = [-1,5,3,4,0]
输出: [-1,0,3,4,5]
示例 3:
输入: head = []
输出: []
提示:
- 链表中节点的数目在范围
[0, 5 * 104]内 -105 <= Node.val <= 105
二、思路分析:
首先这是一道链表相关的题目,但是有涉及到排序的问题,所以我们需要想到哪一种排序方式很适合链表的排序?答案就是归并排序,我们的基本思路如下:
- 首先我们需要设置
快慢指针,然后得到链表的中点,然后将链表一分为二在进行合并的操作 - 在分为
左右链表后,利用递归继续将左右链表在分成两份,直到划分不开左右链表即可 - 这个时候就需要对左右链表进行
排序,我们就判断两个链表的节点值是大还是小,然后创建一个虚拟头节点进行连接,最终的结果就是我们想到的已经排好顺序的链表 这里尤其需要注意设置虚拟头节点的重要性,不然可能会发生错误。
三、代码:
/**
* @param {ListNode} head
* @return {ListNode}
*/
var sortList = function(head) {
if(!head || !head.next) return head
let slow = head, fast = head
let prev = null
while(fast && fast.next){
prev = slow
slow = slow.next
fast = fast.next.next
}
//让两个链表断开
prev.next = null
const l = sortList(head)
const r = sortList(slow)
function merge(l1,l2){
let dummy = new ListNode(-1)
let pre = dummy
while(l1&&l2){
if(l1.val < l2.val){
pre.next = l1
l1 = l1.next
}else{
pre.next = l2
l2 = l2.next
}
pre = pre.next
}
if(l1) pre.next = l1
if(l2) pre.next = l2
return dummy.next
}
//归并排序
return merge(l,r)
};
四、总结:
对于链表的相关题目我们时常会用到
快慢指针,所以我们需要完全掌握快慢指针的妙用,比如可以辩实是否为环形链表,需要找到一个链表的中间位置等等。对于链表排序,我们一般都会采取归并排序来进行排序,因为这样的排序针对链表是最简单。