• 148.排序链表


    题目描述:

    在 O(n log n) 时间复杂度和常数级空间复杂度下,对链表进行排序。

    示例 1:

    输入: 4->2->1->3
    输出: 1->2->3->4
    

    示例 2:

    输入: -1->5->3->4->0
    输出: -1->0->3->4->5

    思路:
      要求 O(n log n) 时间复杂度常数级空间复杂度,首先想到的就是快速排序和归并排序。
      此处使用归并排序,

      归并排序大致思想是: 1.将链表划分左右两部分--> 2.对左右链表进行排序 --> 3.将左右两个有序链表进行合并
      如果三个步骤如果分开实现的,都比较容易,但有人容易在第二步骤懵逼———为什么划分后,对左右链表进行排序,再合并,这不是多此一举么。直接使用第二步对原链表进行排序不就好了?
      
      所以,在归并排序中,实现第二步的实现,其实是靠第三部来完成的。
      当两个链表长度都为1时,即两个链表只有一个结点,那么我们就认为这两个链表是有序的,直接进行 步骤3——将两个有序链表进行合并,于是两个链表合并成了一个长度为2的有序链表。
      
      于是问题转化为,如何把一个长链表 划分为 长度为1的短链表? 很简单,递归划分,不断的将长链表进行二分,最终分成多个长度为1的链表,然后进行合并, 过程类似于二叉树。

      感觉和快速排序的分治思想没有太大区别。

    /**
     * Definition for singly-linked list.
     * public class ListNode {
     *     int val;
     *     ListNode next;
     *     ListNode(int x) { val = x; }
     * }
     */
    class Solution {
        public ListNode sortList(ListNode head) {
            return head == null ? head : merge(head);  
        }
        //划分
        public ListNode merge(ListNode head){
            if (head.next == null) {  //递归退出条件:即链表被划分后只剩一个结点 
                return head;  
            }
            ListNode fast = head, slow = head, pre = head; //这里使用快慢指针 进行链表划分
            while (fast != null && fast.next != null) {
                pre = slow;
                slow = slow.next;
                fast = fast.next.next;
            }
            pre.next = null;     //划分结果是,fast为原链表尾.next, slow为划分后链表右半部分表头,pre为左半部分表尾结点,所以pre.next要为null
            ListNode l = merge(head); //左半部分递归划分 
            ListNode r = merge(slow); //右半部分递归划分
            return mergeList(l,r);  //合并链表 
        }
        //合并 此处f是合并两个有序链表。 
        public ListNode mergeList(ListNode h1,ListNode h2){
            ListNode dummy = new ListNode(0);
            ListNode head = dummy;
            while (h1 != null && h2 != null) {
                if (h1.val < h2.val) {
                    head.next = h1;
                    head = head.next;
                    h1 = h1.next;
                }else {
                    head.next = h2;
                    head = head.next;
                    h2 = h2.next;
                }
            }
            if (h1 == null) {
                head.next = h2;
            }else {
                head.next = h1;
            }
            return dummy.next;
        }
    }
  • 相关阅读:
    【SSRS】入门篇(六) -- 分组和总计
    【SSRS】入门篇(五) -- 设置报表格式
    【SSRS】入门篇(四) -- 向报表添加数据
    【SSRS】入门篇(三) -- 为报表定义数据集
    【SSRS】入门篇(二) -- 建立数据源
    【SSRS】入门篇(一) -- 创建SSRS项目
    【MS SQL】数据库维护计划之数据库备份(二)
    【MS SQL】数据库维护计划之数据库备份(一)
    【MS SQL】查看任务执行进度
    c++ 在客户端的GCC使用
  • 原文地址:https://www.cnblogs.com/magicya/p/10090528.html
Copyright © 2020-2023  润新知