LeetCode_Sorting_148. Sort List 排序链表【快速排序试错,归并排序】【java】【中等】

目录

一,题目描述

英文描述

中文描述

示例与说明

二,解题思路

三,AC代码

Java

四,解题过程

第一博

第二搏


一,题目描述

英文描述

Given the head of a linked list, return the list after sorting it in ascending order.

中文描述

给你链表的头结点 head ,请将其按 升序 排列并返回 排序后的链表 。

进阶:

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

示例与说明

来源:力扣(LeetCode)
链接:力扣
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

二,解题思路

官方给出的题解是归并排序。快速排序很明显会被针对。。。

归并排序的话,主要问题就是如何定位中间位置了。

定位

这里可以采用快慢指针的方法。

初始化在同一位置,快指针一次走两步,慢指针一次走一步。等快指针走到链表末尾,满指针所指节点的下一个节点就是中间位置。

链表合并 

至于链表合并,这个比数组形式还要简单高效,毕竟不需要重开数组。

简单的方法就是声明一个空的头节点和指针p(该指针指向下一个节点要插入的位置),然后不断的移动左右链表的指针即可。

三,AC代码

Java

class Solution {
    public ListNode merge (ListNode p1, ListNode p2) {
        ListNode head = new ListNode(), p = head;
        while (p1 != null && p2 != null) {
            if (p1.val < p2.val) {
                p.next = p1;
                p1 = p1.next;
            } else {
                p.next = p2;
                p2 = p2.next;
            }
            p.next.next = null;
            p = p.next;
        }
        while (p1 != null) {
            p.next = p1;
            p1 = p1.next;
            p.next.next = null;
            p = p.next;
        }
        while (p2 != null) {
            p.next = p2;
            p2 = p2.next;
            p.next.next = null;
            p = p.next;
        }
        return head.next;
    }
    public ListNode mergeSort(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 p1 = mergeSort(slow.next);
        slow.next = null;                                       // 将链表分成两段
        ListNode p2 = mergeSort(head);
        return merge(p1, p2);
    }
    public ListNode sortList(ListNode head) {
        return mergeSort(head);
    }
}

四,解题过程

第一博

先尝试了简单的快速排序方法(选取head作为pivot)

class Solution {
    public ListNode partation (ListNode head, ListNode left, ListNode right) {
        if (head == null) return null;
        ListNode pivot = head,p = head.next, tem;// 选取头节点作为pivot
        while (p != null) {
            tem = p;
            p = p.next;
            if (tem.val < pivot.val) {
                tem.next = left.next;
                left.next = tem;
            } else {
                tem.next = right.next;
                right.next = tem;
            }
        }
        return pivot;
    }
    public ListNode quickSort(ListNode head) {
        if (head == null) return null;
        ListNode left = new ListNode(), right = new ListNode();
        ListNode mid = partation(head, left, right);
        ListNode newLeft = quickSort(left.next);// 递归处理左半部分
        ListNode newRight =  quickSort(right.next);// 递归处理右半部分
        // 将左半部分、pivot、右半部分进行合并
        if (newLeft != null) {
            ListNode tem = newLeft;
            while (tem.next != null) tem = tem.next;
            if (mid != null) {
                tem.next = mid;
                tem = tem.next;
            }
            tem.next = newRight;
        } else if (mid != null) {
            newLeft = mid;
            newLeft.next = newRight;
        } else {
            newLeft = newRight;
        }
        return newLeft;
    }
    public ListNode sortList(ListNode head) {
        return quickSort(head);
    }
}

果然如此。。。妥妥的针对

第二搏

快慢指针+有序链表合并,轻车熟路了 

猜你喜欢

转载自blog.csdn.net/qq_41528502/article/details/121460526