148.排序链表

148.排序链表

题目

给你链表的头结点 head ,请将其按 升序 排列并返回 排序后的链表 。

进阶:

你可以在 O(n log n) 时间复杂度和常数级空间复杂度下,对链表进行排序吗?

示例 1:

image

输入:head = [4,2,1,3]
输出:[1,2,3,4]
示例 2:

image

输入: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
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

题解-递归法

看见排序,想到昨天做的K个链表排序,时间复杂度O(n log n),第一个想到的是归并排序。

  • 对数组做归并排序需要的空间复杂度为O(n)-->新开辟数组O(n)+递归调用函数O(logn);
  • 对链表做归并排序可以通过修改引用来更改节点位置,因此不需要向数组一样开辟额外的O(n)空间,但是只要是递归就需要消耗log(n)的空间复杂度,要达到O(1)空间复杂度的目标,得使用迭代法。

因为之前做了k个链表的排序,使用了递归法,这里就先使用递归法解

问题1:数组的中间点很好找,链表的中间节点怎么找?使用快慢指针

注意:这里需要对链表进行断链,不断链的话,归并时候分左右两边是没有用的!因为左边排序的时候,还是通过左边最后一个节点的next到了右边节点。

public ListNode sortList(ListNode head) {
//递归终止条件
if(head==null||head.next ==null) return head;
//本层递归需要做的事情,断链并合并
ListNode dummy = new ListNode(0);
dummy.next = head;
ListNode slow = dummy;
ListNode fast = dummy;

//或者这样定义快慢指针
//ListNode slow = head;
//ListNode fast = head.next; 


while(fast != null && fast.next != null){
	slow = slow.next;
	fast = fast.next.next;
}
//slow指向的就是中间节点,开始断链,左右两边分别开始排序
fast = slow.next; //记录右边链表的开头
slow.next = null; //断链

ListNode l1 = sortList(head);
ListNode l2 = sortList(fast);
return merge2Lists(l1,l2);//返回合并好的头节点
}
 
ListNode merge2Lists(ListNode l1,ListNode l2){
	ListNode dummy = new ListNode();
	ListNode tail = dummy;
	ListNode tmp;
	while(l1 != null && l2 != null){
		if(l1.val <= l2.val){
			tmp = l1;
			l1 = l1.next;
		} else{
			tmp = l2;
			l2 = l2.next;
		}
		tail.next = tmp;
		tail = tail.next;
	}
	tail.next = l1==null?l2:l1;
	return dummy.next;
}

题解-迭代法

从头开始,先2个节点2个节点分别排序,然后再4个节点,4个节点分别排序...

排序时需要先断链再排序,上面已经描述了。

通过头节点传入需要切的链表,切掉之后就断链了,所以我们需要记录切掉之后的链表用于下次切割。
每次切割的长度是在变化的,这里作为参数传入,返回切割之后剩下的表头

ListNode cut(ListNode head,int size){
	while(--size!=0 && head!=null){
		head = head.next;
	}
	if(head == null) return null;
	ListNode next = head.next;
	head.next = null;
	return next
}

合并两个有序链表

ListNode merge2Lists(ListNode l1,ListNode l2){
	ListNode dummy = new ListNode();
	ListNode tail = dummy;
	ListNode tmp;
	while(l1 != null && l2 != null){
		if(l1.val <= l2.val){
			tmp = l1;
			l1 = l1.next;
		} else{
			tmp = l2;
			l2 = l2.next;
		}
		tail.next = tmp;
		tail = tail.next;
	}
	tail.next = l1==null?l2:l1;
	return dummy.next;
}

从头开始,先2个节点2个节点分别排序,然后再4个节点,4个节点分别排序...

ListNode dummy = new ListNode(0);
dummy.next = head;
int len = 0;
while(head!=null){
	head=head.next;
	len++;
}


for(int i=1;i<len;i*=2){
ListNode l1,l2;
ListNode tail = dummy; //切割之后会断链,tail指向结尾把断链的连成一个链表
ListNode cur = dummy.next; //每一轮切割的节点数增加都要从头开始
	while(cur!=null){
	l1 = cut(cur,i);
	l2 = cut(l1,i);
	tail.next = merge2Lists(cur,l1); //重新连成一个链表
	cur=l2; //下一次循环的切割
	while(tail.next !=null){
		tail =tail.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;
ListNode dummy = new ListNode(0);
dummy.next = head;
int len = 0;
while(head!=null){
	head=head.next;
	len++;
}
for(int i=1;i<len;i*=2){
ListNode l1,l2;
ListNode tail = dummy; 
ListNode cur = dummy.next; 
	while(cur!=null){
	l1 = cut(cur,i);
	l2 = cut(l1,i);
	tail.next = merge2Lists(cur,l1); 
	cur=l2;
	while(tail.next !=null){
		tail =tail.next;
	}
}
}
return dummy.next;
}
	
 ListNode cut(ListNode head,int size){
	while(--size!=0 && head!=null){
		head = head.next;
	}
	if(head == null) return null;
	ListNode next = head.next;
	head.next = null;
	return next;
}
ListNode merge2Lists(ListNode l1,ListNode l2){
	ListNode dummy = new ListNode();
	ListNode tail = dummy;
	ListNode tmp;
	while(l1 != null && l2 != null){
		if(l1.val <= l2.val){
			tmp = l1;
			l1 = l1.next;
		} else{
			tmp = l2;
			l2 = l2.next;
		}
		tail.next = tmp;
		tail = tail.next;
	}
	tail.next = l1==null?l2:l1;
	return dummy.next;
}
}
posted @ 2021-12-13 16:18  rananie  阅读(41)  评论(0)    收藏  举报