• LeetCode148. 排序链表


    链表的归并操作不需要额外空间,因而使用归并排序符合本题常数级空间复杂度的要求。最适合单链表的排序算法是归并排序。

    ☆☆☆思路1:自顶向下的归并排序(递归)     时间复杂度O(nlogn),  空间复杂度O(logn),其中空间复杂度主要取决于递归调用的栈空间。

        主要考察:1)归并排序思想;2)寻找链表中间节点;3)合并两个有序链表

    ☆☆☆☆思路2:自底向上的归并排序(迭代)   时间复杂度O(nlogn),  空间复杂度O(1)

    ☆☆☆☆思路3:单链表的快排实现(面试常考)

    代码1:(归并 递归)

    class Solution {
        public ListNode sortList(ListNode head) {
            if (head == null || head.next == null)
                return head;
            ListNode fast = head, slow = head;
            while (fast.next != null && fast.next.next != null) {
                fast = fast.next.next;
                slow = slow.next;
            }
            ListNode right = slow.next;
            slow.next = null;
            ListNode l1 = sortList(head);
            ListNode l2 = sortList(right);
            return merge(l1, l2);
        }
        //  合并两个有序链表
        public ListNode merge(ListNode l1, ListNode l2) {
            ListNode dummyHead = new ListNode(-1);
            ListNode cur = dummyHead;
            while (l1 != null && l2 != null) {
                if (l1.val < l2.val) {
                    cur.next = l1;
                    l1 = l1.next;
                }else {
                    cur.next = l2;
                    l2 = l2.next;
                }
                cur = cur.next;
            }
            if (l1 != null) cur.next = l1;
            if (l2 != null) cur.next = l2;
            return dummyHead.next;
        }
    }

    代码2:(归并 非递归)

    class Solution {
        public ListNode sortList(ListNode head) {
            if (head == null || head.next == null) return head;
            int len = getLength(head);
            ListNode dummyHead = new ListNode(-1);
            dummyHead.next = head;
            for (int step = 1; step < len; step *= 2) { //依次将链表分成1块,2块,4块...
                //每次变换步长,pre指针和cur指针都初始化在链表头
                ListNode pre = dummyHead, cur = dummyHead.next;
                while (cur != null) {
                    ListNode head1 = cur; //第一部分头(第二次循环之后,cur为剩余部分头,
                    ListNode head2 = split(head1, step); //第二部分头
                    cur = split(head2, step); //剩余部分的头
                    ListNode temp = merge(head1, head2);
                    pre.next = temp;
                    while (pre.next != null) {
                        pre = pre.next;  //把pre指针移动到排序好的部分的末尾
                    }
                }
            }
            return dummyHead.next;
        }
        // 断链操作 返回第二部分链表头
        public ListNode split(ListNode head,int step){
            if (head == null) return head;
            ListNode cur = head;
            for (int i = 1; i < step && cur.next != null; i++) { // 注意 i 从1开始
                cur = cur.next;
            }
            ListNode right = cur.next;
            cur.next = null;
            return right;
        }
        // 获取链表长度
        public int getLength(ListNode head) {
            int len = 1;
            while (head.next != null) {
                head = head.next;
                len ++;
            }
            return len;
        }
        //  合并两个有序链表
        public ListNode merge(ListNode l1, ListNode l2) {
            ListNode dummyHead = new ListNode(-1);
            ListNode cur = dummyHead;
            while (l1 != null && l2 != null) {
                if (l1.val <= l2.val) {
                    cur.next = l1;
                    l1 = l1.next;
                }else {
                    cur.next = l2;
                    l2 = l2.next;
                }
                cur = cur.next;
            }
            if (l1 != null) cur.next = l1;
            if (l2 != null) cur.next = l2;
            return dummyHead.next;
        }
    }

    代码3:(快排)

    具体过程如下:

      1. 将原链表中所有节点依次划分成三个链表,分别为small代表左部分,equal代表中间部分,big代表有部分。

      2. 将small、equal和big三个链表重新串起来即可。

      3. 整个过程需要特别注意对null节点的判断和处理。

    class Solution {
        public ListNode sortList(ListNode head) {
            return quickSort(head)[0];
        }
        private ListNode[] quickSort(ListNode head) {
            if (head == null || head.next == null)
                return new ListNode[]{head, head};
            ListNode[][] parAns = listPartition(head);
            ListNode[] left = quickSort(parAns[0][0]);
            ListNode[] right = quickSort(parAns[2][0]);
            // 小的和相等的重新连接
            if (left[1] != null) {
                left[1].next = parAns[1][0];
                parAns[1][1] = parAns[1][1] != null ? parAns[1][1] : left[1];
            }
            // 所有的重新连接
            if (parAns[1][1] != null) {
                parAns[1][1].next = right[0];
            }
            // 返回的数组中第一个是头节点,第二个是尾节点
            return new ListNode[]{left[0] != null ? left[0] : (parAns[1][0] != null ? parAns[1][0] : right[0]),
                                  right[1] != null ? right[1] : (parAns[1][1] != null ? parAns[1][1] : left[1])};
        }
        private ListNode[][] listPartition(ListNode head) {
            ListNode sH = null; // 小的头
            ListNode sT = null; // 小的尾
            ListNode eH = null; // 相等的头
            ListNode eT = null; // 相等的尾
            ListNode bH = null; // 大的头
            ListNode bT = null; // 大的尾
            ListNode next = null; // 保存下一个节点
            int pivot = head.val;
            while (head != null) {
                next = head.next;
                head.next = null; // 删除可以AC,否则会超时
                if (head.val < pivot) {
                    if (sH == null) {
                        sH = head;
                        sT = head;
                    }else {
                        sT.next = head;
                        sT = head;
                    }
                }else if (head.val == pivot) {
                    if (eH == null) {
                        eH = head;
                        eT = head;
                    }else{
                        eT.next = head;
                        eT = head;
                    }
                }else { // head.val > pivot
                    if (bH == null) {
                        bH = head;
                        bT = head;
                    }else {
                        bT.next = head;
                        bT = head;
                    }
                }
                head = next;
            }
            if (sT != null) sT.next = null;
            if (eT != null) eT.next = null;
            if (bT != null) bT.next = null;
            return new ListNode[][]{{sH,sT},{eH,eT},{bH,bT}};
        }
    }

    单链表快排参考:

        左神书P55

        单链表快排,字节面试原题

  • 相关阅读:
    关于React的脚手架
    yarn和npm
    谈谈NPM和Webpack的关系
    php开发环境和框架phalcon的搭建
    Centos6.5--svn搭建
    System.Diagnostics.Process.Start(ProcessStartInfo)
    PHP错误:call to undefined function imagecreatetruecolor
    PostgreSQL删除表中重复数据行
    URL存在http host头攻击漏洞-修复方案
    for循环的执行顺序
  • 原文地址:https://www.cnblogs.com/HuangYJ/p/14134322.html
Copyright © 2020-2023  润新知