解题思路
自低向上归并,真的很不好写。快把我写吐了。
主要用到两个函数:
cut,把链表按照长度断成一截一截的;
merge,把两个链表归并。
先把链表断开成长度为1的小链表,然后归并一次;再断开成长度为2的,再归并;再断成4,8,16…
具体处理的时候,不是一次把链表断完再归并,而是先断两节,归并一次,再断两节,再归并一次,用一个tail记录之前的链表的尾部,这样可以在归并之后把链表接上。
所以其实每一次操作的时候,链表是有四节的:第1节是已经归并过的链表,第2,3节是断下来的要归并的链表,第3节是还没处理的链表。
这题真的很恶心。
代码
/**
* 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; }
* }
*/
public class Solution {
public ListNode sortList(ListNode head) {
int len = 0;
ListNode dummyHead = new ListNode(0, head);
ListNode dummy = head;
while (dummy != null) {
len++;
dummy = dummy.next;
}
if (len < 2) return head;
//正式处理
for (int i = 1; i < len; i *= 2) {
ListNode cur = dummyHead.next;
ListNode tail = dummyHead;
while (cur != null) {
ListNode left = cur;
ListNode right = cut(cur, i);
cur = cut(right, i);
//把链表接上
tail.next=merge(left, right);
while (tail.next!=null) tail=tail.next;
}
}
return dummyHead.next;
}
public ListNode cut(ListNode head,int length){
while (--length>0 && head!=null) {
head=head.next;
}
if (head==null) return null;
ListNode node = head.next;
head.next=null;
return node;
}
public ListNode merge(ListNode left,ListNode right){
ListNode dummyHead=new ListNode();
ListNode cur= dummyHead;
while (left!=null && right!=null){
if (left.val<=right.val){
cur.next=left;
left=left.next;
}else {
cur.next=right;
right=right.next;
}
cur=cur.next;
}
if (left==null) cur.next=right;
else cur.next=left;
return dummyHead.next;
}
}