LeetCode: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)的,
  • 需要复制出相等的空间来进行赋值归并。对于链表,实际上是可以实现常数空间占用的(链表的归并
  • 排序不需要额外的空间)。利用归并的思想,递归地将当前链表分为两段,然后merge,分两段的方
  • 法是使用 fast-slow 法,用两个指针,一个每次走两步,一个走一步,知道快的走到了末尾,然后
  • 慢的所在位置就是中间位置,这样就分成了两段。merge时,把两段头部节点值比较,用一个 p 指向
  • 较小的,且记录第一个节点,然后 两段的头一步一步向后走,p也一直向后走,总是指向较小节点,
  • 直至其中一个头为NULL,处理剩下的元素。最后返回记录的头即可。
  • 主要考察3个知识点,
  • 知识点1:归并排序的整体思想
  • 知识点2:找到一个链表的中间节点的方法
  • 知识点3:合并两个已排好序的链表为一个新的有序链表

代码:

//递归排序三部曲:1,快慢指针找中点;2,递归调用mergeSort,3,合并两个链表
//需要注意的点:1.递归调用mergeSort的返回值 2.递归合并链表的写法
class Solution {
public:
    ListNode* sortList(ListNode* head) {
        return mergeSort(head);
    }
    
    ListNode* mergeSort(ListNode* node) {
        if (!node || !node->next) return node;
        //快慢指针
        ListNode* fast = node;
        ListNode* slow = node;
        ListNode* breakN = node;
        while (fast && fast->next) {
            fast = fast->next->next;
            breakN = slow;
            slow = slow->next;
        }
        breakN->next = nullptr;
        ListNode *l1 = mergeSort(node);
        ListNode *l2 = mergeSort(slow);
        return merge(l1, l2);
    }
    
    ListNode* merge(ListNode* l1, ListNode* l2) {
        //递归到底的情况
        if (l1 == nullptr) return l2;
        if (l2 == nullptr) return l1;
        //分情况递归实现
        if (l1->val <= l2->val) {
            l1->next = merge(l1->next, l2);
            return l1;
        } else {
            l2->next = merge(l2->next, l1);
            return l2;
        }
    }
}

原文链接:https://leetcode-cn.com/problems/sort-list/comments/

猜你喜欢

转载自blog.csdn.net/liuweiyuxiang/article/details/89057579