题目:
给定链表的头结点 head
,请将其按 升序 排列并返回 排序后的链表 。
示例 :
输入:head = [4,2,1,3] 输出:[1,2,3,4]
思路:
刚开始的想法比较粗暴,遍历链表,再把链表节点val添加到数组,再快排然后给新的链表。可以但是比较麻烦,浪费资源也比较多,不过思路简单而且容易实现,适合面试想不出来嗯写。
看了别人归并排序思路,可以借鉴确实应该好很多。
就是把两表不断分成两部分排序好再合起来,就是递归差不多吧,也好理解的。
详情看代码及注释。
复杂度:
时间:快排O(logn),查找O(n),就是O(n)。
空间:没有额外空间,复杂度O(1)。
代码:
public ListNode sortList(ListNode head) {
//先考虑特殊情况排除掉
//空链表和单值链表不需要考虑
if(head==null || head.next==null){
return head;
}
//spilt()的作用就是将链表分为两半并且返回后半部分
ListNode node1 = head;
ListNode node2 = spilt(head);
//归并过程
node1 = sortList(node1);
node2 = sortList(node2);
//调用一下这个合并两个部分的函数就行了
return merge(node1,node2);
}
//这个返回一半这个可以借助快慢指针,很经典的做法
private ListNode spilt(ListNode head){
ListNode fast = head.next;
ListNode slow = head;
//fast没走到最后一格或者尾结点(null),slow走一格,fast走两格
while(fast!=null&&fast.next!=null){
slow = slow.next;
fast = fast.next.next;
}
//要把slow这个链表取过来,并且将slow指向null,也就是结束了,前面就是前部
ListNode last = slow.next;
slow.next = null;
return last;
}
//把两个链表合并的功能函数
private ListNode merge(ListNode node1,ListNode node2){
ListNode res = new ListNode(0);
ListNode cur = res;
while(node1!=null && node2!=null){
if(node1.val<node2.val){
cur.next = node1;
node1 = node1.next;
}else{
cur.next = node2;
node2 = node2.next;
}
cur = cur.next;
}
cur.next = node1 == null?node2:node1;
return res.next;
}