LeetCode-148. 排序链表-Java-medium

题目链接

法一(归并排序非递归)
    /**
     * 获得链表实际长度
     *
     * @param head
     * @return
     */
    private int length(ListNode head) {
        ListNode cur = head;
        int len = 0;
        while (cur != null) {
            len++;
            cur = cur.next;
        }
        return len;
    }

    /**
     * 将链表切分为两个,需满足前半部分链表节点数量为step,并返回后半部分链表的头节点
     *
     * @param head
     * @param step
     * @return
     */
    private ListNode cut(ListNode head, int step) {
        ListNode cur = head;
        while (--step != 0 && cur != null) { // cur最终指向前半部分链表的尾节点
            cur = cur.next;
        }
        if (cur == null) {
            return null;
        } else {
            ListNode right = cur.next; // right为后半部分链表的头节点
            cur.next = null; // 断链
            return right;
        }
    }

    /**
     * 将两个非递减的单链表归并为一个非递减的单链表,并返回归并后链表的首元结点
     *
     * @param left
     * @param right
     * @return
     */
    private ListNode merge(ListNode left, ListNode right) {
        ListNode dummy = new ListNode();
        ListNode cur = dummy, leftCur = left, rightCur = right;
        while (leftCur != null && rightCur != null) {
            if (leftCur.val < rightCur.val) {
                cur.next = leftCur;
                leftCur = leftCur.next;
            } else {
                cur.next = rightCur;
                rightCur = rightCur.next;
            }
            cur = cur.next;
        }
        cur.next = leftCur != null ? leftCur : rightCur;
        return dummy.next;
    }

    /**
     * 法一(归并排序非递归)
     * (1)归并思路:bottom-to-up
     * (2)例子:[4,3,1,7,8,9,2,11,5,6]
     *     step=1: (3->4)->(1->7)->(8->9)->(2->11)->(5->6)
     *     step=2: (1->3->4->7)->(2->8->9->11)->(5->6)
     *     step=4: (1->2->3->4->7->8->9->11)->(5->6)
     *     step=8: (1->2->3->4->5->6->7->8->9->11)
     * (3)复杂度
     *     最坏情况时间复杂度:O(nlogn)
     *     空间复杂度:O(1)
     *
     * @param head
     * @return
     */
    public ListNode sortList(ListNode head) {
        ListNode dummy = new ListNode(); // 引入虚节点,方便操作
        dummy.next = head;
        int len = length(head);
        for (int step = 1; step < len; step <<= 1) { // step为归并排序步长
            ListNode cur = dummy.next, tail = dummy;
            while (cur != null) {
                ListNode left = cur;
                ListNode right = cut(left, step); // 将链表拆成两部分,left为长度是step的链表,right为剩余链表
                cur = cut(right, step); // 将right继续拆成两部分,最终left和right均为长度是step的链表,cur是剩余链表
                tail.next = merge(left, right); // 将left和right按顺序合并后挂接到tail的尾部
                while (tail.next != null) { // 保持tail为尾部,用于拼接下一趟循环merge后的链表
                    tail = tail.next;
                }
            }
        }
        return dummy.next;
    }
法二(归并排序递归)
    /**
     * 将两个非递减的单链表归并为一个非递减的单链表,并返回归并后链表的首元结点
     *
     * @param left
     * @param right
     * @return
     */
    private ListNode merge(ListNode left, ListNode right) {
        ListNode dummy = new ListNode();
        ListNode cur = dummy, leftCur = left, rightCur = right;
        while (leftCur != null && rightCur != null) {
            if (leftCur.val < rightCur.val) {
                cur.next = leftCur;
                leftCur = leftCur.next;
            } else {
                cur.next = rightCur;
                rightCur = rightCur.next;
            }
            cur = cur.next;
        }
        cur.next = leftCur != null ? leftCur : rightCur;
        return dummy.next;
    }

    /**
     * 快慢指针找到中间节点,并在该位置将链表切分为两个
     *
     * @param head
     * @return
     */
    private ListNode findMiddleNode(ListNode head) {
        ListNode slow = head, fast = head, pre = null;
        while (fast != null && fast.next != null) {
            pre = slow;
            slow = slow.next;
            fast = fast.next.next;
        }
        pre.next = null; // 切断链表
        return slow; // 返回后半部分链表的头节点
    }

    /**
     * 归并排序递归
     *
     * @param head
     * @return
     */
    private ListNode mergeSort(ListNode head) {
        if (head == null || head.next == null) {
            return head;
        }
        ListNode mid = findMiddleNode(head); // 将链表在中间位置分割为前后两部分
        ListNode left = mergeSort(head); // 归并链表前半部分
        ListNode right = mergeSort(mid); // 归并链表后半部分
        return merge(left, right);
    }

    /**
     * 法二(归并排序递归)
     * 最坏情况时间复杂度:O(nlogn)
     * 空间复杂度:O(n)
     *
     * @param head
     * @return
     */
    public ListNode sortList_2(ListNode head) {
        return mergeSort(head);
    }
本地测试
        /**
         * 148. 排序链表
         */
        lay.showTitle(148);
        Solution148 sol148 = new Solution148();
        int[] nums148 = new int[]{-1, 5, 3, 4, 0};
        ListNode head148_1 = new ListNode();
        head148_1 = listOpt.creatListByArray(head148_1, nums148);
        listOpt.showList(head148_1);
        ListNode sortHead148_1 = sol148.sortList(head148_1.next);
        listOpt.showNoHeadList(sortHead148_1);
        ListNode head148_2 = new ListNode();
        head148_2 = listOpt.creatListByArray(head148_2, nums148);
        ListNode sortHead148_2 = sol148.sortList_2(head148_2.next);
        listOpt.showNoHeadList(sortHead148_2);
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值