力扣148

在 O(n log n) 时间复杂度和常数级空间复杂度下,对链表进行排序。

示例 1:

输入: 4->2->1->3
输出: 1->2->3->4

此题对时间复杂度和空间复杂度有严格限制。普通归并排序可以满足时间复杂度,但不满足O(n)空间复杂度。故选择从低至顶的归并排序。从长度为1,为2,为4逐渐归并,详细操作如代码所示。
package Leetcode;

public class sortList {
public ListNode sortList(ListNode head) {
// 增加头结点
ListNode pre = new ListNode(0);
pre.next = head;
ListNode preNode = pre;

/*循环增加排序子链表的长度
(preNode = sortSubList(preNode, len)) != null 作为边界条件,
意为第一次调用sortSubList就返回null,说明链表长度小于len*2,可以结束排序
*/
for (int len = 1; (preNode = sortSubList(preNode, len)) != null; len *= 2){
while (preNode != null){
preNode = sortSubList(preNode, len);
}
preNode = pre;
}
return pre.next;
}

// 返回排序后的链表的最后一个节点
ListNode sortSubList(ListNode pre, int num){
//当前指针位置
int fstnum = 0, lstnum = 0;
//当前节点
ListNode fst = pre.next, lst = fst;

//找到lst节点位置
for (int i = 0; i < num; i++){
//fst长度不够,直接返回null,此时子链表已经是排好序的
if (lst == null)
return null;
lst = lst.next;
}
//比较,终止条件为fstnum或lastnum大于子链表长度,或者lsatnum到达链表末尾
while (fstnum < num && lstnum < num && lst != null){
if (fst.val <= lst.val){
pre.next = fst;
fst = fst.next;
fstnum++;
}
else{
pre.next = lst;
lst = lst.next;
lstnum++;
}
pre = pre.next;
}

//如果fst子链表还有剩余节点,接到当前节点后面
if (fstnum < num){
pre.next = fst;
//让当前节点走到子链表末尾
for (; fstnum < num; fstnum++)
pre = pre.next;
//接上后面的链表
pre.next = lst;
}

//和上面类似,此时还需考虑last子链表长度小于num的情况
if (lstnum < num && lst != null){
pre.next = lst;
for (; lstnum < num && pre != null; lstnum++)
pre = pre.next;
}

//返回最后一个节点,作为下次排序的pre
return pre;
}

public static void main(String[] args) {
ListNode l1 = new ListNode(4);
ListNode l2 = new ListNode(2);
ListNode l3 = new ListNode(1);
ListNode l4 = new ListNode(3);
l1.next=l2;
l2.next=l3;
l3.next=l4;
sortList s = new sortList();
s.sortList(l1);
}
}
posted @ 2020-02-26 21:21  HEUzbc  阅读(166)  评论(0)    收藏  举报