题目要求:
对单链表进行从小到大排序,要求时间复杂度O(N*logN),空间复杂度O(1);
思路:
因时间复杂度要求为O(N*logN),简单排序(时间复杂度为O(N*N))均不可用,
故可以考虑归并排序的思想,归并排序对数组操作空间复杂度为O(n),但对链表为O(1),因为每次只在merge函数中创建了一个辅助的链表头结点ListNode temp=new ListNode(0);
归并排序的一般步骤为:
1)将待排序数组(链表)取中点并一分为二;
2)递归地对左半部分进行归并排序;
3)递归地对右半部分进行归并排序;
4)将两个半部分进行合并(merge),得到结果。
所以对应此题目,可以划分为三个小问题:
1)找到链表中点 (快慢指针思路,快指针一次走两步,慢指针一次走一步,快指针在链表末尾时,慢指针恰好在链表中点);
2)写出merge函数,即如何合并链表。
3)写出mergesort函数,实现上述步骤。
代码如下:
/*
* Definition for singly-linked list.
* class ListNode {
* int val;
* ListNode next;
* ListNode(int x) {
* val = x;
* next = null;
* }
* }
*/
public class Solution {
public ListNode sortList(ListNode head) {
//mergesort 空间复杂度为1;
if(head==null||head.next==null)
return head;
ListNode mid=findMid(head);
ListNode left=head;
ListNode right=mid.next;
mid.next=null;
left=sortList(left);
right=sortList(right);
head=merge(left,right);
return head;
}
//若链表节点为奇数,则找到中间节点;若链表节点为偶数,则找到两个中间节点的前一个;
public ListNode findMid(ListNode head)
{
ListNode prear=head;
ListNode pfront=head;
while(prear.next!=null&&prear.next.next!=null)
{
prear=prear.next.next;
pfront=pfront.next;
}
return pfront;
}
public ListNode merge(ListNode left,ListNode right)
{
if(left==null)
return right;
if(right==null)
return left;
//相较数组,并没有辅助数组的赋值操作,空间复杂度为O(1);
ListNode temp=new ListNode(0);
ListNode p=temp;
while(left!=null&&right!=null)
{
if(left.val<right.val)
{
p.next=left;
p=p.next;
left=left.next;
}else
{
p.next=right;
p=p.next;
right=right.next;
}
}
if(left!=null)
{
p.next=left;
}
if(right!=null)
{
p.next=right;
}
return temp.next;
}
}
时间: 2024-12-14 10:45:29