力扣148. 排序链表
在 O(nlogn) 时间复杂度和常数级空间复杂度下,对链表进行排序。
示例 1:
输入: 4->2->1->3
输出: 1->2->3->4
示例 2:
输入: -1->5->3->4->0
输出: -1->0->3->4->5
分析
题目要求时间复杂度是O(nlogn),就需要二分,既然是二分,就确定了归并排序。
空间复杂度要求O(1),就不能使用递归,并且不能创建额外的空间来保存临时数组。
题目是对链表进行排序,链表可以通过指针指向新节点进行排序,所以实现了O(1)的空间复杂度。
既然不能用递归,就根据递归的思想,从底向上进行归并。
第一轮循环,我们处理没两个节点,将节点两两排序。
第二轮循环,现在节点是两两有序,我们就每四个进行排序。
直到我们的排序规模超过了链表长度,就说明链表全部有序。
原链表: 4 -> 2 ||-> 1 -> 3
第一轮排序后: 2 -> 4 ||-> 1 -> 3
第二轮排序: 1 -> 2 -> 3 -> 4
原链表: -1 -> 5 ||-> 3 -> 4|| -> 0
第一轮排序后: -1 -> 5 || -> 3 -> 4 || -> 0
第二轮排序后: -1 -> 3 -> 4 -> 5 || -> 0
第三轮排序后: -1 -> 0 -> 3 -> 4 -> 5
注意:
寻找每两个待合并的链表时,要时刻注意越界问题。链表1可能长度不够排序规模,链表2也可能不够排序规模。
代码
class Solution {
public ListNode
sortList(ListNode head
) {
if(head
== null
|| head
.next
== null
){
return head
;
}
int len
= 0;
ListNode tmp
= head
;
while(tmp
!= null
){
len
++;
tmp
= tmp
.next
;
}
ListNode dumHead
= new ListNode(0);
dumHead
.next
= head
;
int sortLen
= 1;
while(sortLen
<len
){
ListNode pre
= dumHead
;
ListNode h
= dumHead
.next
;
while(h
!=null
){
ListNode h1
= h
;
int i
= sortLen
;
while(i
>0){
if(h
== null
) break;
h
= h
.next
;
i
--;
}
if(i
>0) break;
ListNode h2
= h
;
i
= sortLen
;
while(i
>0){
if(h
== null
) break;
h
= h
.next
;
i
--;
}
int c1
= sortLen
;
int c2
= sortLen
- i
;
while(c1
> 0 && c2
> 0) {
if(h1
.val
< h2
.val
) {
pre
.next
= h1
;
h1
= h1
.next
;
c1
--;
}else {
pre
.next
= h2
;
h2
= h2
.next
;
c2
--;
}
pre
= pre
.next
;
}
pre
.next
= c1
> 0 ? h1
: h2
;
while(c1
> 0 || c2
> 0) {
pre
= pre
.next
;
c1
--;
c2
--;
}
pre
.next
= h
;
}
sortLen
*=2;
}
return dumHead
.next
;
}
}