LeetCode Sort List

本文介绍了一种在O(n log n)时间内使用常量空间复杂度对链表进行排序的方法,利用归并排序将链表一分为二,再递归地排序并合并。通过快慢指针法找到链表中点,并详细解析了合并两个已排序链表的过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Sort a linked list in O(n log n) time using constant space complexity.

思路分析:这题要求在O(n log n) 和常量空间对单链表排序,O(n log n) 的排序算法有快速排序,归并排序和堆排序,对于快速排序,其最坏情况下的时间复杂读是O(n),所以不符合要求。我们可以用归并排序解决这题。用归并排序的好处是平均时间和最坏时间都是O(n log n) ,并且我们不需要额外空间就可以merge两个有序的链表使得merge之后仍然有序。这里插一句,链表和数组的区别在于链表不支持元素按照index随机访问,因此实现依赖于index访问元素的算法会比较麻烦,但是链表也有其自身的优势,就是在任意位置插入或者删除元素都是常量时间,因为不需要移动大量元素“腾地方”。在数组上实现归并排序和在链表上实现归并排序基本算法一致,都是先不断对半划分数组,直到每个元组只剩下一个元素的时候开始merge元素,递归划分,划分完毕进行merge。下图给出的算法过程的形象表示(来自这里):


划分的过程数组和链表是类似的,只是我们需要找到链表的中点,这个可以用快慢指针法解决。划分完毕后merge的过程二者有不同,对于数组我们会使用额外tmp数组保存merge之后的数组结果,merge结束后拷贝回原来数组。对于链表,我们不需要额外空间,那么如何merge两个有序链表使得merge之后仍然有序呢?这就是LeetCode Merge Two Sorted List 问题,我以merge1 3 5 和 2 4 6的过程为例,单步图解如下


理解了快慢指针找链表中点,merge两个sorted list的过程和merge sort的划分合并过程后,解决这题就很容易了。

AC Code

/**
 * Definition for singly-linked list.
 * class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) {
 *         val = x;
 *         next = null;
 *     }
 * }
 */
public class Solution {
    public ListNode sortList(ListNode head) {
        return mergeSortList(head);
    }
    
    public ListNode mergeSortList(ListNode head) {//split the list into two partitions
        if(head == null || head.next == null) return head;
        ListNode fast = head;
        ListNode slow = head;
        while(fast.next != null && fast.next.next != null){//fast must arrive the end firstly
            fast = fast.next;
            fast = fast.next;
            slow = slow.next;
        }
        ListNode head1 = head;
        ListNode head2 = slow.next;
        slow.next = null;//split the list from the middle node
        head1 = mergeSortList(head1);
        head2 = mergeSortList(head2);
        return merge(head1, head2);
    }
    
    public ListNode merge(ListNode head1, ListNode head2){
        ListNode fakeHead = new ListNode(0);
        fakeHead.next = head1;
        ListNode pre = fakeHead;
        while(head1 != null && head2 != null){
            if(head1.val < head2.val){
                head1 = head1.next;
            } else {
                ListNode next = head2.next;
                head2.next = pre.next;
                pre.next = head2;
                head2 = next;
            }
            pre = pre.next;
        }
        if(head2 != null){
            pre.next = head2;
        }
        return fakeHead.next;
    }
}

解题过程中参考了 http://blog.youkuaiyun.com/linhuanmars/article/details/21133949 但是这个解法由于是递归实现,仍然需要(O(logn))的栈空间。迭代实现的解法可以参考 这里

### 使用 `sort` 函数在 LeetCode 上实现数组或列表排序 #### C++ 实现 在 C++ 中,可以使用标准库中的 `std::sort()` 来对向量 (vector) 进行排序。此函数采用迭代器作为参数来指定要排序的范围。 ```cpp class Solution { public: void sortVector(std::vector<int>& vec) { std::sort(vec.begin(), vec.end()); // 对整个vec升序排列 } }; ``` 上述代码展示了如何定义一个名为 `Solution` 的类,并在其内部创建了一个成员函数 `sortVector`,该函数接收一个整数类型的引用向量并对其进行排序[^1]。 为了降序排列,则需提供自定义比较谓词: ```cpp bool descending(int a, int b){ return a > b; } //... std::sort(vec.begin(), vec.end(), descending); ``` 这里通过传递第三个参数给 `std::sort()`, 即实现了按特定规则(这里是大于号表示的大于关系)来进行排序操作。 #### Python 实现 Python 提供了内置的方法 `.sort()` 和全局函数 `sorted()` 可用于原地修改对象或返回新的已排序序列副本。下面的例子展示怎样在一个解决方案类里调用这些功能: ```python from typing import List class Solution: def sortList(self, lst: List[int]): lst.sort() # 原位排序lst @staticmethod def get_sorted_copy(lst: List[int]) -> List[int]: return sorted(lst) # 返回一个新的有序列表而不改变原始数据 ``` 这段代码同样构建了一个叫做 `Solution` 的类,在其中包含了两种不同的方式来处理输入列表 `lst`:一种是在原有基础上直接进行排序;另一种则是生成一份经过排序的新列表副本[^2]。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值