https://leetcode.com/problems/sort-list/

Sort a linked list in O(n log n) time using constant space complexity.

解题思路:

常见的O(nlogn)算法,快速排序、归并排序,堆排序。大概讲讲优缺点,在数据量很大并且很乱的时候,快速排序有着最快的平均速度,比如Java和C++语言的库排序函数就主要是快排,但基本上是优化过的,因为快排有缺点。对于本来就已经排好序的数列,快排反而要花到O(n^2)的时间,因为如果总是选取第一个元素作为pivot,每次只能将n的数列化为1和n-1两部分,而不是相等的两部分。而且快速排序不是稳定的,因为pivot最后被交换到某一个位置,是不确定的。由于快速排序一般用递归,所以需要O(logn)的额外空间,(递归树的高度)。最坏情况需要O(n),也就是上面说的情况,递归树一边倒。

堆排序在最坏情况下,也能有O(nlogn)的时间,这点比快排好,而且不需要额外的存储空间。但是它也是不稳定的。

归并排序用在数组上的时候,好处就是稳定的,而且最坏情况下,也能有O(nlogn)的时间,这点比快排好。但是它需要花O(n)的额外空间,来存放归并的结果。但是用在链表上的时候,可以不需要这O(n)的空间,因为链表的排序完全可以做到随意移动-插入,类似in-place。归并排序还有一个重要的用途,用在外排序上,比如海量数据存在n个文件中。

好了,看题目,这道题是链表,用归并排序是最合适的。题目 Merge Two Sorted Lists 中我们已经解决了,两个已经排序的链表的归并,那么这道题就是类似数组归并排序的概念,用递归从顶之下。将原链表不断分成两个链表,再分为两个,直到只有一个元素。然后再从低至上,两两归并排序它们,直到合成一个整的。

这里要注意理解的就是,每个递归的返回值应该怎么用。

  1. /**
  2. * Definition for singly-linked list.
  3. * class ListNode {
  4. * int val;
  5. * ListNode next;
  6. * ListNode(int x) {
  7. * val = x;
  8. * next = null;
  9. * }
  10. * }
  11. */
  12. public class Solution {
  13. public ListNode sortList(ListNode head) {
  14. return mergeSortList(head);
  15. }
  16.  
  17. public ListNode mergeSortList(ListNode head){
  18. if(head == null || head.next == null) {
  19. return head;
  20. }
  21. ListNode fast = head;
  22. ListNode slow = head;
  23. //取终点的方法,是判断fast.next和fast.next.next,而不是fast和fast.next
  24. while(fast.next != null){
  25. fast = fast.next;
  26. if(fast.next != null){
  27. fast = fast.next;
  28. slow = slow.next;
  29. }
  30. }
  31. ListNode mid = slow.next;
  32. //重要,将原链表从中间断开,可以不要考虑前后两段的连接了,这个问题交给下面的mergeList方法
  33. slow.next = null;
  34. head = mergeSortList(head);
  35. mid = mergeSortList(mid);
  36. return mergeList(head, mid);
  37. }
  38.  
  39. public ListNode mergeList(ListNode l1, ListNode l2) {
  40. ListNode dummy = new ListNode(0);
  41. ListNode current = dummy;
  42. while(l1 != null && l2 != null){
  43. if(l1.val < l2.val){
  44. current.next = l1;
  45. l1 = l1.next;
  46. current = current.next;
  47. }else{
  48. current.next = l2;
  49. l2 = l2.next;
  50. current = current.next;
  51. }
  52. }
  53. if(l1 != null){
  54. current.next = l1;
  55. }else{
  56. current.next = l2;
  57. }
  58. return dummy.next;
  59. }
  60. }

update 2015/06/21:

三刷,把取中间节点的方法提取了出来。

  1. /**
  2. * Definition for singly-linked list.
  3. * public class ListNode {
  4. * int val;
  5. * ListNode next;
  6. * ListNode(int x) { val = x; }
  7. * }
  8. */
  9. public class Solution {
  10. public ListNode sortList(ListNode head) {
  11. if(head == null || head.next == null) {
  12. return head;
  13. }
  14. ListNode mid = getMidNode(head);
  15. head = sortList(head);
  16. mid = sortList(mid);
  17. return mergeList(head, mid);
  18. }
  19.  
  20. public ListNode getMidNode(ListNode head) {
  21. if(head == null || head.next == null) {
  22. return head;
  23. }
  24. ListNode slow = new ListNode(0);
  25. slow.next = head;
  26. while(head != null) {
  27. head = head.next;
  28. if(head != null) {
  29. head = head.next;
  30. slow = slow.next;
  31. }
  32. }
  33. ListNode res = slow.next;
  34. slow.next = null;//这一步很重要
  35. return res;
  36. }
  37.  
  38. public ListNode mergeList(ListNode l1, ListNode l2) {
  39. ListNode dummy = new ListNode(0);
  40. ListNode current = dummy;
  41. while(l1 != null && l2 != null){
  42. if(l1.val < l2.val){
  43. current.next = l1;
  44. l1 = l1.next;
  45. current = current.next;
  46. }else{
  47. current.next = l2;
  48. l2 = l2.next;
  49. current = current.next;
  50. }
  51. }
  52. if(l1 != null){
  53. current.next = l1;
  54. }else{
  55. current.next = l2;
  56. }
  57. return dummy.next;
  58. }
  59. }

//20180920

https://www.geeksforgeeks.org/merge-sort/

注意的是针对链表的归并取的并不是mid node,而是mid的下一个node。

归并的一般步骤

  1. MergeSort(arr[], l, r)
  2. If r > l
  3. 1. Find the middle point to divide the array into two halves:
  4. middle m = (l+r)/2
  5. 2. Call mergeSort for first half:
  6. Call mergeSort(arr, l, m)
  7. 3. Call mergeSort for second half:
  8. Call mergeSort(arr, m+1, r)
  9. 4. Merge the two halves sorted in step 2 and 3:
  10. Call merge(arr, l, m, r)
  1. /**
  2. * Definition for singly-linked list.
  3. * public class ListNode {
  4. * int val;
  5. * ListNode next;
  6. * ListNode(int x) { val = x; }
  7. * }
  8. */
  9. class Solution {
  10. public ListNode sortList(ListNode head) {
  11. if (head == null || head.next == null) {
  12. return head;
  13. }
  14. ListNode midNext = findMidNext(head);
  15. ListNode head1 = sortList(head);
  16. ListNode head2 = sortList(midNext);
  17. return merge(head1, head2);
  18. }
  19.  
  20. public ListNode findMidNext(ListNode head) {
  21. if (head == null || head.next == null) {
  22. return head;
  23. }
  24. ListNode dummy = new ListNode(-1);
  25. dummy.next = head;
  26. ListNode fast = head;
  27. ListNode slow = head;
  28. while (fast.next != null && fast.next.next != null) {
  29. fast = fast.next.next;
  30. slow = slow.next;
  31. }
  32. ListNode midNext = slow.next;
  33. slow.next = null;
  34. return midNext;
  35. }
  36.  
  37. public ListNode merge(ListNode head1, ListNode head2) {
  38. ListNode dummy = new ListNode(-1);
  39. ListNode iter = dummy;
  40. while (head1 != null && head2 != null) {
  41. if (head1.val <= head2.val) {
  42. iter.next = head1;
  43. head1 = head1.next;
  44. } else {
  45. iter.next = head2;
  46. head2 = head2.next;
  47. }
  48. iter = iter.next;
  49. }
  50. if (head1 == null) {
  51. iter.next = head2;
  52. } else {
  53. iter.next = head1;
  54. }
  55. return dummy.next;
  56. }
  57. }

Sort List 典型链表的更多相关文章

  1. 9. Sort List && Insertion Sort List (链表排序总结)

    Sort List Sort a linked list in O(n log n) time using constant space complexity.                   H ...

  2. leetcode:Sort List(一个链表的归并排序)

    Sort a linked list in O(n log n) time using constant space complexity. 分析:题目要求时间复杂度为O(nlogn),所以不能用qu ...

  3. sort list(给链表排序)

    Sort a linked list in O(n log n) time using constant space complexity. 题目要求使用O(nlogn)时间复杂度,可以考虑使用归并排 ...

  4. leetcode Sort List 对链表进行排序

    描述: Sort a linked list in O(n log n) time using constant space complexity. 在O(n*log(n))的时间复杂度,常数级空间复 ...

  5. 45.Sort List(链表排序)

    Level:   Medium 题目描述: Sort a linked list in O(n log n) time using constant space complexity. Example ...

  6. leetcode——Insertion Sort List 对链表进行插入排序(AC)

    Sort a linked list using insertion sort. class Solution { public: ListNode *insertionSortList(ListNo ...

  7. Leetcode148. Sort List排序链表

    在 O(n log n) 时间复杂度和常数级空间复杂度下,对链表进行排序. 示例 1: 输入: 4->2->1->3 输出: 1->2->3->4 示例 2: 输入 ...

  8. Leetcode147. Insertion Sort List对链表进行插入排序

    对链表进行插入排序. 从第一个元素开始,该链表可以被认为已经部分排序(用黑色表示). 每次迭代时,从输入数据中移除一个元素(用红色表示),并原地将其插入到已排好序的链表中. 插入排序算法: 插入排序是 ...

  9. Java数据结构和算法 - 链表

    Q: 为什么要引入链表的概念?它是解决什么问题的? A: 数组作为数据存储结构有一定的缺陷,在无序数组中,搜索是低效的:而在有序数组中,插入效率又很低:不管在哪一个数组中删除效率都很低:况且一个数组创 ...

随机推荐

  1. js 的静态获取和动态获取

    静态获取方法 document.getElementById obj.querySelector obj.querySelectorAll 动态获取方法(每次使用时候会回去重新获取一次) obj.ge ...

  2. [C++] 化学方程式的格式化算法

    网上普遍使用的化学方程式的格式普遍如下 例: KMnO4+FeSO4+H2SO4=Fe2(SO4)3+MnSO4+K2SO4+H2O 要把化学方程式格式化,单单一个正则表达式是非常反人类的,故可选用 ...

  3. Mybatis中and和or的细节处理

    当一条SQL中既有条件查又有模糊查的时候,偶尔会遇到这样的and拼接问题.参考如下代码: <select id="listSelectAllBusiness"> sel ...

  4. python3的dict

    dict1 = {getlistUrl:getlistData,getskuUrl:getskuData, approveUrl:approveData, approvedlistUrl:approv ...

  5. Shock wave

    ** shock wave thickness of shock wave is order of 1e-7 m why governed by Euler Equation? P334 shock ...

  6. vue-router2.0二级路由的简单使用

    1.app.vue中 <template> <div id="app"> <router-view></router-view> & ...

  7. 洛谷 1541 NOIp2010提高组 乌龟棋

    [题解] 很容易想到这是一个DP,f[i][j][k][l]表示4种卡片分别用了多少张,那么转移方程就是f[i][j][k][l]=Max(f[i-1][j][k][l],f[i][j-1][k][l ...

  8. 《AlwaysRun!》第八次团队作业:Alpha冲刺 第一天

    项目 内容 这个作业属于哪个课程 老师链接 这个作业的要求在哪里 实验十二 团队作业8:软件测试与Alpha冲刺 团队名称 Always Run! 作业学习目标 (1)掌握软件测试基础技术 (2)学习 ...

  9. [luoguP2701] [USACO5.3]巨大的牛棚Big Barn(DP)

    传送门 经典问题. 找出最大的不包含 1 的正方形. f[i][j] 表示 以 (i,j) 结尾的最大的不包含 1 的正方形 f[i][j] = min(f[i - 1][j], f[i][j - 1 ...

  10. 超级钢琴(codevs 2934)

    题目描述 Description 小Z是一个小有名气的钢琴家,最近C博士送给了小Z一架超级钢琴,小Z希望能够用这架钢琴创作出世界上最美妙的音乐. 这架超级钢琴可以弹奏出n个音符,编号为1至n.第i个音 ...