给你链表的头结点 head ,请将其按 升序 排列并返回 排序后的链表 。
进阶:
你可以在 O(n log n) 时间复杂度和常数级空间复杂度下,对链表进行排序吗?
示例 1:
输入:head = [4,2,1,3]
输出:[1,2,3,4]
示例 2:
输入:head = [-1,5,3,4,0]
输出:[-1,0,3,4,5]
示例 3:
输入:head = []
输出:[]
思路- 迭代+拆分+归并
- 按1 2 4…步长归并
- 迭代拆分逐块归并,再将每一块拼接
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode() {}
* ListNode(int val) { this.val = val; }
* ListNode(int val, ListNode next) { this.val = val; this.next = next; }
* }
*/
class Solution {
public ListNode sortList(ListNode head) {
int len=getLength(head);
//亚节点标记头
ListNode dHead=new ListNode(-1);
dHead.next=head;
//按步长循环分块归并
for(int step=1;step<len;step*=2){
//每次归并完重新重新拆分
ListNode pre=dHead;
ListNode cur=dHead.next;
//按步长迭代拆分归并
while(cur!=null){
//第一部分头
ListNode h1=cur;
//第二部分头
ListNode h2=split(h1,step);
//剩余部分的头:迭代下次拆分
cur=split(h2,step);
//归并
ListNode mergeHead=merge(h1,h2);
//整个链表连接
pre.next=mergeHead;
while(pre.next!=null){
pre=pre.next;
}
pre.next=cur;
}
}
return dHead.next;
}
//获取链表长度
public int getLength(ListNode head){
int len=0;
while(head!=null){
len++;
head=head.next;
}
return len;
}
//拆分
public ListNode split(ListNode head,int step){
if(head==null){
return null;
}
ListNode cur=head;
for(int i=1;i<step;i++){
if(cur.next!=null){
cur=cur.next;
}
}
ListNode right=cur.next;
cur.next=null;
return right;
}
//归并操作
public ListNode merge(ListNode l1,ListNode l2){
ListNode dHead=new ListNode(-1);
ListNode tmp=dHead;
while(l1!=null&&l2!=null){
if(l1.val<l2.val){
tmp.next=l1;
tmp=l1;
l1=l1.next;
}else{
tmp.next=l2;
tmp=l2;
l2=l2.next;
}
}
if(l1==null){
tmp.next=l2;
}
if(l2==null){
tmp.next=l1;
}
return dHead.next;
}
}
复杂度
时间复杂度O(n log n):外层log n内层n
空间复杂度O(1)