在O(n log n)的时间内使用常数级空间复杂度对链表进行排序。
public class Solution {
public ListNode sortList(ListNode head) {
if(head == null || head.next == null) {
return head;
}
ListNode mid = getMid(head);
ListNode midNext = mid.next;
mid.next = null;
return mergeSort(sortList(head), sortList(midNext));
}
private ListNode getMid(ListNode head) {
if(head == null || head.next == null) {
return head;
}
ListNode slow = head, quick = head;
while(quick.next != null && quick.next.next != null) {
slow = slow.next;
quick = quick.next.next;
}
return slow;
}
private ListNode mergeSort(ListNode n1, ListNode n2) {
ListNode preHead = new ListNode(0), cur1 = n1, cur2 = n2, cur = preHead;
while(cur1 != null && cur2 != null) {
if(cur1.val < cur2.val) {
cur.next = cur1;
cur1 = cur1.next;
} else {
cur.next = cur2;
cur2 = cur2.next;
}
cur = cur.next;
}
cur.next = cur1 == null ? cur2 : cur1;
return preHead.next;
}
}
思路扔是归并排序,递归实现,跟前面的都一样。
但是大家好像都会在归并的时候将归并好的放在新链表里,这会造成内存泄露。
好的方法是:归并的时候不要重新放在新链表,而是将右链表的元素都插入左链表中,
仍然在原来的链表中操作,可以杜绝了内存泄露的危险。具体看代码中的merge_list函数。
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
//找到链表中间位置
ListNode *find_middle(ListNode *head)
{
//使用快,慢指针的方法:慢指针走一步,快指针走两步
ListNode *slow = head, *fast = head;
while(fast != NULL && fast->next != NULL && fast->next->next != NULL)
//第三个条件都满足才能++,否则对于两个元素不能平分
{
slow = slow->next;
fast = fast->next->next;
}
return slow;
}
//合并两个有序链表:前提是两个链表本身必须有序
ListNode *merge_list(ListNode *&arg_left, ListNode *arg_right)
{
if(arg_right == NULL)
{
return arg_left;
}
ListNode *pre_left = arg_left;//左链表当前节点的上一个节点
ListNode *left = arg_left, *right = arg_right;
while(left != NULL && right != NULL)
{
if(left->val > right->val)
//为减少内存开辟,直接将右链表小值插入左链表中
{
if(left == arg_left)
//left位于左链表头结点
{
arg_left = right;
ListNode *tmp_right = right;
right = right->next;
tmp_right->next = left;
pre_left = tmp_right;
}
else
{
ListNode *tmp_right = right;
right = right->next;
pre_left->next = tmp_right;
tmp_right->next = left;
pre_left = tmp_right;
}
}
else
{
pre_left = left;
left = left->next;
}
}
if(left == NULL)
//如果左链表遍历完
{
pre_left->next = right;
}
return arg_left;
}
ListNode *sortList(ListNode *head) {
//归并排序
if(head == NULL || head->next == NULL)
//空链表或者只有一个元素
{
return head;
}
ListNode *middle = find_middle(head);//找到链表中间位置
ListNode *right = sortList(middle->next);
middle->next = NULL;
ListNode *left = sortList(head);
return merge_list(left, right);
}
};
class Solution {
public:
ListNode *merge(ListNode *list1,ListNode *list2)
{
if(list1==nullptr)
return list2;
if(list2==nullptr)
return list1;
if(list1->val < list2->val)
{
list1->next = merge(list1->next,list2);
return list1;
}
else
{
list2->next = merge(list1,list2->next);
return list2;
}
}
ListNode *sortList(ListNode *head)
{
if(!head || !head->next)
return head;
ListNode *slow=head,*fast=head;
while(fast->next && fast->next->next)
{
slow = slow->next;
fast = fast->next->next;
}
fast = slow->next;
slow->next = nullptr;
slow = head;
ListNode *left = sortList(slow);
ListNode *right = sortList(fast);
return merge(left,right);
}
};
ListNode* merge(ListNode *h1, ListNode *h2)
{
if(h1 == NULL) return h2;
else if(h2 == NULL) return h1;
else
{
ListNode *dummy = new ListNode(-1);
ListNode *p = dummy;
while(h1 && h2)
{
if(h1->val < h2->val)
{
p->next = h1;
h1 = h1->next;
}
else
{
p->next = h2;
h2 = h2->next;
}
p = p->next;
}
if(h1) p->next = h1;
if(h2) p->next = h2;
return dummy->next;
}
}
ListNode *sortList(ListNode *head) {
if(head == NULL || head->next == NULL)
return head;
// 时间复杂度为O(nlogn) 空间复杂度O(1)
// 可以用归并排序思想做
// 第一步:快慢指针找中点
ListNode *f = head, *s = head;
while(f->next && f->next->next)
{
f = f->next->next;
s = s->next;
}
// 注意前一半链表尾结点的next置NULL
f = s->next; // 后一半链表
s->next = NULL; // 前一半链表
ListNode *head1 = sortList(head);
ListNode *head2 = sortList(f);
// 第二步:归并
return merge(head1, head2);
}
import java.util.*;
/*
* public class ListNode {
* int val;
* ListNode next = null;
* }
*/
public class Solution {
/**
*
* @param head ListNode类
* @return ListNode类
*/
public ListNode sortList (ListNode head) {
// write code here
if(head == null || head.next == null) return head;
ListNode slow = head;
ListNode fast = head.next;
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;
}
} import java.util.*;
/*
* public class ListNode {
* int val;
* ListNode next = null;
* }
*/
public class Solution {
/**
*
* @param head ListNode类
* @return ListNode类
*/
public ListNode sortList (ListNode head) {
// write code here
if(head==null || head.next==null) return head;
ListNode mid = findMidList(head);
//断开
ListNode midNext = mid.next;
mid.next=null;
return mergeList(sortList(head),sortList(midNext));
}
public ListNode findMidList(ListNode h){
if(h==null || h.next==null) return h;
ListNode l1 =h;
ListNode l2 =h;
while(l2.next!=null && l2.next.next!=null){
l1=l1.next;
l2=l2.next.next;
}
return l1;
}
public ListNode mergeList(ListNode left,ListNode right){
ListNode head ,relist;//结果
if(left==null)return right;
if(right==null)return left;
ListNode f1=left.next,f2=right.next;
//头结点判断
if(left.val<right.val){
relist=head=left;
f2=right;
}else{
relist=head=right;
f1=left;
}
while(f1!=null && f2 !=null){
if(f1.val<f2.val){
relist.next=f1;
relist=relist.next;
f1 = f1.next;
}else{
relist.next=f2;
relist=relist.next;
f2 = f2.next;
}
}
if(f1!=null){
relist.next=f1;
}
if(f2!=null){
relist.next=f2;
}
return head;
}
} import java.util.*;
/*
* public class ListNode {
* int val;
* ListNode next = null;
* }
*/
public class Solution {
/**
*
* @param head ListNode类
* @return ListNode类
*/
public ListNode sortList (ListNode head) {
if(head == null || head.next == null){
return head;
}
//定义快慢指针
ListNode slow = head;
ListNode fast = head;
while(fast.next != null && fast.next.next != null){
slow = slow.next;
fast = fast.next.next;
}
//定义中间节点(切割点)
ListNode mid = slow.next;
//从中间将链表切开
slow.next = null;
//递归寻找左半边链表和右半边链表的中间节点
ListNode left = sortList(head);
ListNode right = sortList(mid);
//建立一个辅助节点作为头节点
ListNode h = new ListNode(0);
ListNode result = 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上
//到此就完成了一次归并,递归操作会继续下次归并
h.next = left != null ? left : right;
//返回h作为头部的下个节点h.next。
return result.next;
}
}
class Solution {
public:
// 自底向上的两路归并算法,非递归版
ListNode *dummyNode = new ListNode(-1); // 保存
ListNode *sortList(ListNode *head) {
// 构建一个空的头结点,以减少各类边界条件的判断,
// 能够方便地遍历和截断链表
ListNode *dn = new ListNode(-1), *prev = dn;
dn -> next = head;
int len = 0;
while (prev -> next != nullptr) {
prev = prev -> next;
len++;
}
prev = dn;
for (int i = 1; i < len; i *= 2) {
while (prev -> next != nullptr) {
ListNode *l1 = splitP(prev, i);
ListNode *l2 = splitP(prev, i);
ListNode *mergedHead = merge(l1, l2);
// 将合并的链表还原到原链表
dummyNode -> next -> next = prev -> next;
prev -> next = mergedHead;
prev = dummyNode -> next;
}
prev = dn;
}
delete dummyNode;
return dn -> next;
}
// 从head链表中截取从head -> next开始的size个结点,并返回其头结点
ListNode *splitP(ListNode *head, int size) {
int step = size;
ListNode *p = head -> next, *new_head;
while (--step && p != nullptr) {
p = p -> next;
}
new_head = head -> next;
if (p != nullptr) {
head -> next = p -> next;
p -> next = nullptr;
} else {
head -> next = nullptr;
}
return new_head;
}
// 合并两个链表,并返回合并后的新链表的头结点
ListNode *merge(ListNode* p1, ListNode *p2) {
ListNode *dummyHead = new ListNode(-1), *tail = dummyHead;
dummyHead -> next = nullptr;
ListNode *l1 = p1, *l2 = p2;
while (l1 != nullptr && l2 != nullptr) {
if (l1 -> val < l2 -> val) {
tail -> next = l1;
l1 = l1 -> next;
} else {
tail -> next = l2;
l2 = l2 -> next;
}
tail = tail -> next;
}
if (l1 != nullptr) tail -> next = l1;
if (l2 != nullptr) tail -> next = l2;
while (tail != nullptr) {
dummyNode -> next = tail;
tail = tail -> next;
}
return dummyHead -> next;
}
}; public class Solution {
public ListNode sortList(ListNode head) {
if (head == null) {
return null;
}
return mergeSort(head);
}
public ListNode mergeSort(ListNode head) {
if (head.next == null) {
return head;
}
ListNode pre = null;
ListNode slow = head;
ListNode fast = head;
while (fast != null && fast.next != null) {
pre = slow;
slow = slow.next;
fast = fast.next.next;
}
pre.next = null;
ListNode l1 = mergeSort(head);
ListNode l2 = mergeSort(slow);
return merge(l1, l2);
}
public ListNode merge(ListNode l1, ListNode l2) {
ListNode dummy = new ListNode(0);
ListNode cur = dummy;
while (l1 != null && l2 != null) {
if (l1.val < l2.val) {
cur.next = l1;
cur = cur.next;
l1 = l1.next;
} else {
cur.next = l2;
cur = cur.next;
l2 = l2.next;
}
}
if (l1 != null) {
cur.next = l1;
}
if (l2 != null) {
cur.next = l2;
}
return dummy.next;
}
}
纪念第一次用 java 刷题:
public class Solution {
public ListNode sortList(ListNode head) {
if(head == null || head.next == null){
return head;
}
ListNode leftHead = null, rightHead = null, curNode = head.next;
while(curNode != null){
ListNode next = curNode.next;
if(curNode.val < head.val){
if(leftHead != null){
curNode.next = leftHead;
leftHead = curNode;
}else{
leftHead = curNode;
curNode.next = null;
}
}else{
if(rightHead != null){
curNode.next = rightHead;
rightHead = curNode;
}else{
rightHead = curNode;
curNode.next = null;
}
}
curNode = next;
}
leftHead = sortList(leftHead);
rightHead = sortList(rightHead);
head.next = rightHead;
if(leftHead != null){
curNode = leftHead;
while(curNode.next != null){
curNode = curNode.next;
}
curNode.next = head;
}else{
leftHead = head;
}
return leftHead;
}
}
public class Solution {
public ListNode sortList(ListNode head) {
if (head==null) return null;
return fen( head );
}
public ListNode bing(ListNode start,ListNode left)
{
ListNode s = start;
ListNode l = left;
ListNode node = null;
while(start!=null && left!=null)
{
if(start.val<=left.val) {
if(node!=null) node.next = start;
node = start;
start = start.next;
}else{
if(node!=null) node.next = left;
node = left;
left = left.next;
}
}
if(start==null) node.next=left;
if(left==null) node.next=start;
if (s.val<=l.val) return s;
return l;
}
public ListNode fen(ListNode node)
{
if(node.next==null) return node;
ListNode root = node.next;
node.next = null;
ListNode q = bing( node,fen( root ) );
return q;
}
}
我也不知道我的答案满不满足题意,反正我过了,嘿嘿
参考前面两位大佬写的,有一些小毛病修正了一下
1、sortList函数中的head指针传进来需要先判断是否为空,或者下一节点是否为空,否则会发生段错误;
2、快慢指针寻找时,也要判断快慢指针是否为空,以及快指针下一节点是否为空;
class Solution {
public:
ListNode *sortList(ListNode *head) {
if(head == NULL || head->next == NULL)
return head;
ListNode* slow = head;
ListNode* fast = head->next;
while(fast!=NULL && fast->next!=NULL && slow != NULL)
{
fast = fast->next->next;
slow = slow->next;
}
ListNode* left = sortList(slow->next);
slow->next = NULL;
ListNode* right = sortList(head);
return mergeTwoList(left,right);
}
ListNode *mergeTwoList(ListNode* left,ListNode *right)
{
ListNode* dummy = new ListNode(0);
ListNode* p = dummy;
while(left && right)
{
if (left->val > right->val)
{
p->next = right;
right = right->next;
}
else
{
p->next = left;
left = left->next;
}
p = p->next;
}
if (left == NULL)
p->next = right;
if (right == NULL)
p->next = left;
return dummy->next;
}
}; Sort a linked list in O(n log n) time using constant space complexity.
Example 1:
Input: 4->2->1->3
Output: 1->2->3->4
Example 2:
Input: -1->5->3->4->0
Output: -1->0->3->4->5
最近忙着追《都挺好》,差点忘记每天的任务。这一题要求时间复杂度为O(n log n) 并且用常数级别的空间复杂度。对于链表这种数据结构,不像数组那么方便,因此堆排序以及快速排序不是很方便,因此这一题用归并排序比较合适,并且对于本题,空间上不需要用数组来存储,因此是常数级别的。
class Solution {
//归并排序的归过程
public ListNode sortList(ListNode head) {
//1.判定是否为空或者只有一个元素,这也是归并排序中归的停止条件
if(head == null || head.next == null){
return head;
}
//2.将链表截成两段
ListNode pre = null;
ListNode slow = head;
ListNode fast = head;
while(fast != null && fast.next != null){
pre = slow;
slow = slow.next;
fast = fast.next.next;
}
//3.此时pre跟slow指的一样,现在将链表从中间断开
pre.next = null;
//4.继续再对上面分开的链表再分
ListNode l1 = sortList(head);
ListNode l2 = sortList(slow);
//5.递归分开之后就应该按照一定的规则合并了
return merge(l1,l2);
}
//归并排序的并过程
private ListNode merge(ListNode l1,ListNode l2){
//新建一个结点用于串联并过程结果
ListNode tmp = new ListNode(0);
ListNode p = tmp;
//并的过程,谁小谁就接到p后面
while(l1!=null && l2!=null){
if(l1.val < l2.val){
p.next = l1;
l1 = l1.next;
}else{
p.next = l2;
l2 = l2.next;
}
p = p.next;
}
//如果有一段没有结束,直接接到后面即可
if(l1 != null){
p.next = l1;
}
if(l2 != null){
p.next = l2;
}
//返回下一个结点
return tmp.next;
}
}
public class Solution {
public ListNode sortList(ListNode head) {
ListNode low = head, fast = head, pre = null, p = head;
if (head == null || head.next == null)
return head;
while (fast != null && fast.next != null) {
pre = low;
low = low.next;
fast = fast.next.next;
}
ListNode right = sortList(pre.next);
pre.next = null;
ListNode left = sortList(p);
return MergeList(left, right);
}
public ListNode MergeList(ListNode l1, ListNode l2) {
if (l1 == null)
return l2;
if (l2 == null)
return l1;
ListNode head = new ListNode(0), h = head, p1 = l1, p2 = l2, t;
while (p1 != null && p2 != null) {
if (p1.val < p2.val) {
t = new ListNode(p1.val);
p1 = p1.next;
} else {
t = new ListNode(p2.val);
p2 = p2.next;
}
h.next = t;
h = h.next;
}
while (p1 != null) {
t = new ListNode(p1.val);
h.next = t;
p1 = p1.next;
h = h.next;
}
while (p2 != null) {
t = new ListNode(p2.val);
h.next = t;
p2 = p2.next;
h = h.next;
}
return head.next;
}
}
public class Solution {
public ListNode sortList(ListNode head) {
if(head==null || head.next==null) return head;
//首先找到链表的分割中点:快指针一次走两步,慢指针一次走一步
ListNode slow = head;
ListNode fast = head;
while(fast.next!=null && fast.next.next!=null) {
fast = fast.next.next;
slow = slow.next;
}
//以slow.next作为分割链表的中点
ListNode head1 = head;
ListNode head2 = slow.next;
slow.next = null;
//递归地对左半部分进行归并排序
ListNode left = sortList(head1);
//递归地对右半部分进行归并排序
ListNode right = sortList(head2);
//调用自定义的mergeList方法,将左右两个部分进行合并,得到结果并返回结果
return mergeList(left, right);
}
//mergeList方法实现两个有序链表的合并
public ListNode mergeList(ListNode head1, ListNode head2) {
if(head1 == null) return head2;
if(head2 == null) return head1;
ListNode newHead = new ListNode(0);
ListNode p1 = newHead;
while(head1!=null && head2!=null) {
if(head1.val < head2.val) {
p1.next = head1;
head1 = head1.next;
}else {
p1.next = head2;
head2 = head2.next;
}
p1 = p1.next;
}
if(head1!=null) p1.next = head1;
if(head2!=null) p1.next = head2;
return newHead.next;
}
}
void sorttest(vector<int>&p,int s,int m ,vector<int>&q) {
if (s<m){
int mid=(m+s)/2;
sorttest(p,s,mid,q);
sorttest(p,mid+1,m,q);
int l = s;
int f = s;
int r = mid+1;
while(l<=mid && r<=m){
if(p[l]>p[r])
q[s++]=p[r++];
else
q[s++]=p[l++];
}
if(l<=mid) while(l<=mid) q[s++]=p[l++];
if(r<=m) while(r<=m) q[s++]=p[r++];
while(f<=s) {p[f]=q[f];f++;}
}
}
ListNode *sortList(ListNode *head) {
if (!head || !head->next) return head;
vector<int>p;
ListNode *h=head;
while(h!=NULL) { p.push_back(h->val);h=h->next;}
vector<int>q = p;
sorttest(p,0,p.size()-1,q);
ListNode *f=head;
int i = 0;
while(f!=NULL) {f->val = p[i];f=f->next;i++;}
return head;
}
// Sort List - 链表归并排序
/*
因为题目要求复杂度为O(nlogn),故可以考虑归并排序的思想。
归并排序的一般步骤为:
1)将待排序数组(链表)取中点并一分为二;
2)递归地对左半部分进行归并排序;
3)递归地对右半部分进行归并排序;
4)将两个半部分进行合并(merge),得到结果。
*/
// 合并两个有序链表
ListNode* mergeList(ListNode* list1, ListNode* list2) {
if (list1 == nullptr) return list2;
if (list2 == nullptr) return list1;
ListNode* head = new ListNode(-1);
ListNode* tmp = head;
while (list1 && list2) {
if (list1->val < list2->val) {
tmp->next = list1;
list1 = list1->next;
} else {
tmp->next = list2;
list2 = list2->next;
}
tmp = tmp->next;
}
if (list1) tmp->next = list1;
if (list2) tmp->next = list2;
return head->next;
}
// 归并排序
ListNode* mergeSortList(ListNode* head) {
if (!head || !head->next) return head;
// 找到中间节点, 定位到中间节点的前驱节点
ListNode* fast = head, * slow = head;
while (fast->next && fast->next->next) {
fast = fast->next->next;
slow = slow->next;
}
ListNode* mid = slow->next; // 中间节点
slow->next = nullptr; // 断开链表
// 递归地对左右半部分进行归并排序
ListNode* list1 = mergeSortList(head);
ListNode* list2 = mergerSortList(mid);
// 合并左右部分的有序链表
ListNode* sortedList = mergeList(list1, list2);
return sortedList;
}
public class Solution {
public ListNode sortList(ListNode head) {
if(head == null)
return null;
if(head.next == null)
return head;
ListNode p1 = head, p2 = head;
while(p2 != null) { //p1为慢指针,p2快指针,利用快慢指针找中点
p2 = p2.next;
if(p2 != null) //判断p2是否走到空指针,防止空指针异常
p2 = p2.next;
if(p2 != null) //如果p2走到null,p1就不再向前走,否则会在链表结点数为2时出现死循环
p1 = p1.next;
}
//将链表从中点一分为二
p2 = p1.next;
p1.next = null;
return orderedSort(sortList(head), sortList(p2));
}
private ListNode orderedSort(ListNode l1, ListNode l2) {
//合并两个有序链表
ListNode p1 = l1, p2 = l2, tmp = null, head = null, p = null;
while(p1 != null && p2 != null) {
if(p1.val < p2.val) {
tmp = p1; //摘下小结点
p1 = p1.next;
} else {
tmp = p2;
p2 = p2.next; }
if(head == null) {
head = tmp;
p = tmp;
}
else {
p.next = tmp;
p = p.next;
} }
if(p1 != null)
p.next = p1;
if(p2 != null)
p.next = p2;
return head;
}
}