当前位置:网站首页>LeetCode-归并排序链表
LeetCode-归并排序链表
2022-07-02 04:23:00 【Master_hl】
题目描述
示例分析

题目要求
一看见时间复杂度为O(N*logN),而处于这个时间复杂度的排序只有三个:堆排、快排、归并排序,快排最坏情况下,是O(N^2),而堆排不适合链表的排序,所以只剩下归并排序了。
方法一:自顶而下(递归)
自顶而下的方式,就是将链表在递出去的过程中不断拆分成两半,直到只剩下最后两个结点的时候才开始归回来合并,在归回来的时候,左右两个序列段都已经分别有序了,所以合并过程就是将两个有序序列段合并。但是这样做还是达不到完成这个题的要求,这里只是提供一种递归的思路,后面会给出迭代的思路。
代码实现
public ListNode sortList(ListNode head) {
if(head == null || head.next == null) return head;
ListNode slow = head;
ListNode fast = head.next;
//快慢指针来分割链表
while(fast != null && fast.next != null) {
slow = slow.next;
fast = fast.next.next;
}
ListNode midR = slow.next;
slow.next = null;//将中间结点置空是下次递归 return 的必要条件
ListNode left = sortList(head);
ListNode right = sortList(midR);
//合并
ListNode newHead = new ListNode(0);
ListNode prev = newHead;;
while(left != null && right != null) {
if(left.val <= right.val) {
prev.next = left;
left = left.next;
} else {
prev.next = right;
right = right.next;
}
prev = prev.next;
}
//走到这里,两个有序序列,一个为空,一个不为空,把不为空的接在prev的后面
prev.next = (left != null ? left : right);
return newHead.next;
}画图分析

上图分析了左半部分递出去的过程,2和5合并完之后成为一个有序序列段,而 midR 这一边是一个单独的只有一个结点的有序序列段,所以就印证了前面的解释。
复杂度分析
- 时间复杂度:O(N*logN) ,就是归并排序的时间复杂度。
- 空间复杂度:O(logN),每一层的合并都用到了辅助结点,所以空间复杂度就是树的高度。
方法二:自底而上(迭代)
自顶而下为什么做不到常数个空间的空间复杂度呢,因为每递归一次,就要开辟一个辅助的栈空间,并且先执行一个函数的左,右边还没执行,所以栈空间就没有被回收,就必然导致空间复杂度较迭代来说要高。迭代的方式不像递归那样先操作整条链表,再不断细分,而是先两两有序,再四个四个有序...,最后当subLen = 链表长度的一半时,执行完本次循环,就全部有序。
代码实现
public ListNode sortList(ListNode head) {
if (head == null) {
return head;
}
int len = 0;
ListNode node = head;
while (node != null) {
len++;
node = node.next;
}
ListNode newHead = new ListNode(0, head);
//每次循环不断让左右序列扩大两倍
for (int subLen = 1; subLen < len; subLen <<= 1) {
ListNode prev = newHead;
ListNode cur = newHead.next;
while (cur != null) {
ListNode head1 = cur;
//移动到左子序列的尾巴
for (int i = 1; i < subLen && cur.next != null; i++) {
cur = cur.next;
}
ListNode head2 = cur.next;
//分割
cur.next = null;
cur = head2;
//移动到右子序列的尾巴
for (int i = 1; i < subLen && cur != null && cur.next != null; i++) {
cur = cur.next;
}
//用next记录下一次待合并的两序列中左序列的头
ListNode next = null;
if (cur != null && cur.next != null) {
next = cur.next;
cur.next = null;
}
ListNode merged = merge(head1, head2);
//将合并的序列串在辅助结点之后
prev.next = merged;
while (prev.next != null) {
prev = prev.next;
}
cur = next;
}画图分析

从图中可以明显看出迭代与递归的区别,也印证了前面说的先两两有序,再四个四个有序,当subLen = 1/2 len 的时候,执行完本次循环就全部有序。且迭代真正做到了开辟常数个栈空间。
复杂度分析
- 时间复杂度: O(N*logN)
- 空间复杂度: O(1)
本篇完!!!
边栏推荐
猜你喜欢

Yyds dry inventory compiler and compiler tools

QT designer plug-in implementation of QT plug-in

Yolov5网络修改教程(将backbone修改为EfficientNet、MobileNet3、RegNet等)

Fluent icon demo

The solution to the complexity brought by lambda expression

office_ Delete the last page of word (the seemingly blank page)

Realizing deep learning framework from zero -- Introduction to neural network

Spring moves are coming. Watch the gods fight

Yolov5 network modification tutorial (modify the backbone to efficientnet, mobilenet3, regnet, etc.)

Opencv learning example code 3.2.4 LUT
随机推荐
Actual combat | use composite material 3 in application
Wechat applet pull-down loading more waterfall flow loading
蓝湖的安装及使用
60后关机程序
unable to execute xxx. SH: operation not permitted
How much is the tuition fee of SCM training class? How long is the study time?
CorelDRAW Graphics Suite2022免费图形设计软件
JVM knowledge points
Okcc why is cloud call center better than traditional call center?
Wpviewpdf Delphi and Net PDF viewing component
Pytoch --- use pytoch to predict birds
Introduction to JSON usage scenarios and precautions
Pytorch-Yolov5從0運行Bug解决:
PR zero foundation introductory guide note 2
6月书讯 | 9本新书上市,阵容强大,闭眼入!
藍湖的安裝及使用
Feature Engineering: summary of common feature transformation methods
【c语言】动态规划---入门到起立
[untitled]
Monkey test