leetcode第148题,排序链表,java实现

15 篇文章 0 订阅

题目链接

运行结果

执行结果:通过
执行用时 :993 ms, 在所有 Java 提交中击败了5.82%的用户
内存消耗 :39.8 MB, 在所有 Java 提交中击败了98.65%的用户

代码与注释

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) { val = x; }
 * }
 */
// 归并排序
class Solution {
    public ListNode sortList(ListNode head) {
        // 如果链表为null直接返回null。
        if (head == null) return head;
        // 否则返回归并排序后结果
        return mergeSort(head);
    }
    // 第一步:递归分割
    public ListNode mergeSort(ListNode head)
    {
        // 基线条件
        if (head.next == null) return head;

        // 递归将现有链表划分为子链表
        ListNode p1 = head; // 左指针
        ListNode p2 = head.next; // 右指针

        // 找到链表的中点
        if (p2 != null && p2.next != null) 
        {
            p1 = p1.next;
            p2 = p2.next.next;
        }
        ListNode left = head; // 左链表的头节点
        ListNode right = p1.next; // 右链表的头节点
        p1.next = null; // 断开链表中间点

        left = mergeSort(left);
        right = mergeSort(right); 

        return merge(left, right);
    }
    // 第二步:归并
    public ListNode merge(ListNode left, ListNode right)
    {
        // 返回用头结点
        ListNode head = null;
        // 找到头结点
        if (left.val < right.val)
        {
            head = left;
            left = left.next;
        }
        else 
        {
            head = right;
            right = right.next;
        }
        ListNode tmp = head;
        // 两边都不到链表尾
        while (left != null && right != null)
        {
            if (left.val < right.val)
            {
                tmp.next = left;
                left = left.next;
            }
            else
            {
                tmp.next = right;
                right = right.next;
            }
            tmp = tmp.next;
        }
        // 某一边已经到链表尾
        tmp.next = left != null ? left : right;
        return head;
    }
}

做题体会

  1. 题目要求时间复杂度为O(nlogn),空间复杂度为常数阶O(1),上述解答的空间复杂度不满足要求,使用的递归分解,空间复杂度为O(logn)。
  2. 用归并法排序,主要思想分为两步:分割和归并。分割:把待排序数据分割为两个部分,对两个子部分再做同样的分割,直至不能再划分为止。归并:通过比较,将子部分依次归并为一个大的有序部分,再对较大的有序部分执行同样的操作直至整个数据有序。
  3. 分割采用快慢指针法,快指针到达链表末尾时,慢指针到达链表的中部,通过慢指针指向的下一个节点为null,断开链表为两个部分,需要注意的是,初始化快指针为head.next,是为了防止只有两个节点的链表发生分割错误。
  4. 在归并时,当某一边的链表已经到达尾部,只需要将结果链表指向另一边链表的头部即可,无需再做循环判断。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值