问题描述
给你链表的头结点 head
,请将其按 升序 排列并返回 排序后的链表 。
输入:
输出: [-1,0,3,4,5]
/**
* 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) {
// 如果head或head.next
if (head == null || head.next == null) {
return head;
}
// 快慢指针分割链表
// 1. 找到中点
ListNode slow = head,fast = head.next;
while(fast != null && fast.next != null) {
slow = slow.next;
fast = fast.next.next;
}
// 2. 分割慢指针
ListNode tmp = slow.next;
slow.next = null;
// 递归分割
ListNode left = sortList(head);
ListNode rigth = sortList(tmp);
// 合并
ListNode res = new ListNode(-1), h = res;
while(left != null && rigth != null) {
if(left.val < rigth.val) {
h.next = left;
left = left.next;
}else {
h.next = rigth;
rigth = rigth.next;
}
h = h.next;
}
h.next = (left == null) ? rigth : left;
return res.next;
}
}
总结
解题策略:
1. 链表寻找中点:快慢指针
当节点总数为奇数,fast指针走(奇数-1)/2下
当节点总数为偶数,fast指针走(偶数/2) 下
2. 对链表排序:递归归并
时间复杂度 : nlogn
递归理解
场景
战争时期,团长需要知道前方的战况,但是他自己无法确定,所以打电话给营长;
同理,营长打电话给连长...直到联系到侦察兵
于是,有了这么一条联系链 : 团长 -> 营长 -> 连长 -> 排长 -> 班长 -> 侦察兵
找到侦察兵后再把战况级级往左回传,直至传到团长 (营长 : 团长,秀芹嫂子在城楼上面 !)
最后, 团长 : 二营长,你他娘的意大利炮呢? 开炮 ! ! (嘿嘿~~)
大概就是这么个流程~~
团长 (需要知道问题的答案) -> 营长 (往右递归) -> 连长 (往右递归) -> 排长 (往右递归) -> 班长 (往右递归) -> 侦察兵(直至遇到递归出口)
团长(解决问题) <- (回传)营长 <- (回传)连长 <- (回传)排长 <- (回传)班长 <- (回传) 侦察兵
解析
递归实质上也是这样,
当团长不知道战况时(复杂的问题不能一步解决时),
就联系下级(就把问题简单化),
直到联系到侦察兵(直到遇到递归出口),
然后把战况一级一级往上传(然后接近最底层的递归结果往左传),
直至传到团长(最后递归完成)
小匠收工~~