给你链表的头结点 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 = []
输出:[]
提示:
链表中节点的数目在范围 [0, 5 * 104] 内
-105 <= Node.val <= 105来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/sort-list
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
简单做法:
public ListNode sortList(ListNode head) { if(head == null || head.next == null){ return head; } List<ListNode> list = new ArrayList<ListNode>(); while(head != null){ list.add(head); head = head.next; } Collections.sort(list,(item1,item2) -> (item1.val - item2.val)); for(int i = 1; i < list.size(); i++){ list.get(i-1).next = list.get(i); } list.get(list.size() -1 ).next = null; return list.get(0); }
//首先先用昨天的题目的排序方式写一遍、发现时间超限 public ListNode sortList(ListNode head) { if(head == null || head.next == null){ return head; } //我们使用 fast,slow 快慢双指针法,奇数个节点找到中点,偶数个节点找到中心左边的节点。 ListNode fast = head.next; ListNode slow = head; while(fast != null && fast.next != null){ fast = fast.next.next; slow = slow.next; } //将链表分割,分为左边和右边 ListNode temp = slow.next; slow.next = null;//分割需要设置为null ListNode left = sortList(head); ListNode right = sortList(temp); //进行左边和右边链表的整和 ListNode h = new ListNode(); ListNode result = h; //这个循环没有问题 while(left != null && right != null){ if(left.val < right.val){ h.next = left; left = left.next; }else { h.next = right; right = right.next; } h = h.next; } //这里有一些疑问: h.next = left || h.next = right 为什么要这么设置,这两种设置效果是一样的 //因为在循环结束时,有可能因为right为空了,或者left为空了,导致没有给h.next 赋值,所以,再这里复制。 h.next = right != null ? right : left; return result.next; }
时间复杂度:O(logn)
空间复杂度:O(logn)
以上算法的整体思想是:找到中心点,将链表分割,将分割后的链表排序,最后合并.