我是憨批 复习看不下去也看不懂
1.题目
https://leetcode-cn.com/problems/sort-list/
2.方法一:自顶向下归并排序
分析
我第一反应也是归并排序,但是不知道链表长度。。这里用到了快慢指针啊。
对链表自顶向下归并排序的过程如下。
找到链表的中点,以中点为分界,将链表拆分成两个子链表。寻找链表的中点可以使用快慢指针的做法,快指针每次移动2 步,慢指针每次移动 1步,当快指针到达链表末尾时,慢指针指向的链表节点即为链表的中点。
对两个子链表分别排序。
将两个排序后的子链表合并,得到完整的排序后的链表。
复杂度
时间复杂度:O(nlogn),其中 n 是链表的长度。
空间复杂度:O(logn),其中 n 是链表的长度。空间复杂度主要取决于递归调用的栈空间。
代码
/**
* 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) {
return sortList(head, null);
}
public ListNode sortList(ListNode head, ListNode tail){
if(head==null)
return head;
//应该是因为 merge那里的mid是被重复用了两次,所以这么写 。
//防止进入递归之后重复排序,进入递归之后,前一半有mid值,后一半也有mid值,选择把前一段的拿掉
if(head.next==tail){
head.next=null;
return head;
}
ListNode slow=head,fast=head;
while(fast!=tail){
slow=slow.next;
fast=fast.next;
if(fast!=tail)
fast=fast.next;
}
ListNode mid=slow;
ListNode list1=sortList(head,mid);
ListNode list2=sortList(mid,tail);
return merge(list1,list2);
}
public ListNode merge(ListNode head,ListNode mid){
if(head==mid)
return head;
ListNode t1=new ListNode();
ListNode tmp=t1;
while(head!=null&&mid!=null){
if(head.val<=mid.val){
t1.next=head;
head=head.next;
}
else{
t1.next=mid;
mid=mid.next;
}
t1=t1.next;
}
if(head!=null){
t1.next=head;
}
if(mid!=null){
t1.next=mid;
}
return tmp.next;
}
}
class Solution {
public ListNode sortList(ListNode head) {
if (head == null || head.next == null)
return head;
ListNode fast = head.next, slow = head;
while (fast != null && fast.next != null) {
slow = slow.next;
fast = fast.next.next;
}
ListNode tmp = slow.next;
slow.next = null;
ListNode left = sortList(head);
ListNode right = sortList(tmp);
ListNode h = new ListNode(0);
ListNode res = 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 != null ? left : right;
return res.next;
}
}
结果
3.自底向上归并排序
我不会
分析
复杂度
时间复杂度:O(nlogn),其中 n 是链表的长度。
空间复杂度:O(1)。
代码
class Solution {
public ListNode sortList(ListNode head) {
if (head == null) {
return head;
}
int length = 0;
ListNode node = head;
while (node != null) {
length++;
node = node.next;
}
ListNode dummyHead = new ListNode(0, head);
for (int subLength = 1; subLength < length; subLength <<= 1) {
ListNode prev = dummyHead, curr = dummyHead.next;
while (curr != null) {
ListNode head1 = curr;
for (int i = 1; i < subLength && curr.next != null; i++) {
curr = curr.next;
}
ListNode head2 = curr.next;
curr.next = null;
curr = head2;
for (int i = 1; i < subLength && curr != null && curr.next != null; i++) {
curr = curr.next;
}
ListNode next = null;
if (curr != null) {
next = curr.next;
curr.next = null;
}
ListNode merged = merge(head1, head2);
prev.next = merged;
while (prev.next != null) {
prev = prev.next;
}
curr = next;
}
}
return dummyHead.next;
}
public ListNode merge(ListNode head,ListNode mid){
if(head==mid)
return head;
ListNode t1=new ListNode();
ListNode tmp=t1;
while(head!=null&&mid!=null){
if(head.val<=mid.val){
t1.next=head;
head=head.next;
}
else{
t1.next=mid;
mid=mid.next;
}
t1=t1.next;
}
if(head!=null){
t1.next=head;
}
if(mid!=null){
t1.next=mid;
}
return tmp.next;
}
}