「LeetCode」148-排序链表

127 阅读1分钟

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第9天,点击查看活动详情

一.题目:

148. 排序链表 给你链表的头结点 head ,请将其按 升序 排列并返回 排序后的链表 。 示例 1:

image.png

输入: head = [4,2,1,3]
输出: [1,2,3,4]

示例 2:

image.png

输入: 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)
};

四、总结:

对于链表的相关题目我们时常会用到快慢指针,所以我们需要完全掌握快慢指针的妙用,比如可以辩实是否为环形链表,需要找到一个链表的中间位置等等。对于链表排序,我们一般都会采取归并排序来进行排序,因为这样的排序针对链表是最简单。