给你链表的头结点 head ,请将其按 升序 排列并返回 排序后的链表 。
进阶:你可以在
时间复杂度和常数级空间复杂度下,对链表进行排序吗?
示例 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
如果不考虑时空复杂度,最简单直接的方式便是:
- 遍历链表获取所有节点的值
- 将所有节点值进行升序排列
- 利用排序后的结果重构新的链表
此时,时间复杂度为,空间复杂度为
,其中
为链表的长度。
解题代码如下:
/*** 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) {if(head == null || head.next == null)return head;List<Integer> list = new ArrayList<>();ListNode cur = head;while(cur != null){list.add(cur.val);cur = cur.next;}list.sort((o1, o2) -> o1-o2);ListNode dummy = new ListNode();cur = dummy;for(Integer e : list){cur.next = new ListNode(e);cur = cur.next;}return dummy.next;}}
如果要求在的时间复杂度内完成链表的排序,那么上述的方法显然就无法满足了。而常用的满足
时间复杂度要求的排序算法有快速排序、堆排序和归并排序,该题可以采用归并排序的思想来降低时间复杂度。
采用归并排序来解决链表升序排列的整体思路如下:
- 采用快慢指针来寻找链表中点
- 将中点左右的两个有序子链表合并
- 设置好递归出口,即:
,表示链表为空
- 或者
,表示只包含一个节点
有序链表合并的过程就是不断的遍历两个链表,选择当前的最小的的节点作为结果链表的,直到两个链表中的节点全部遍历完毕。
解题代码如下:
/*** 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) {if(head == null || head.next == null)return head;return sortList(head, null);}public ListNode sortList(ListNode head, ListNode tail){// 递归出口if(head == null)return head;if(head.next == tail){head.next = null;return head;}// 平均断开链表// 快慢指针寻找中点ListNode slow = head;ListNode fast = head;while (fast != tail) {slow = slow.next;fast = fast.next;if (fast != tail) {fast = fast.next;}}ListNode left = sortList(head, slow);ListNode right = sortList(slow, tail);ListNode mer = mergeList(left, right);return mer;}public ListNode mergeList(ListNode left, ListNode right){ListNode dummy = new ListNode();ListNode cur = dummy;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 = left;} else if(right != null){cur.next = right;}return dummy.next;}}
