问题描述:

思路:

拿之前那道“对链表插入排序”的代码可以直接通过,但是不符合题目的要求:时间复杂度控制在O(nlogn),插入排序时间复杂度在o(n^2),又因为此时是对链表不是数组,所以考虑到使用归并排序。

归并的两种解法:自顶向下递归和自底向上的迭代,其中递归法也不满足题目要求的o(1)级别的空间复杂度,故只有迭代才是满足题意的,对于递归的归并,书写代码难度更低,迭代实则是模拟一边全过程要考虑的边界情况都比较多细节可能出错的地方也很多。

下面找到两幅图来说明递归和迭代法:

对于递归来说,只需要找到其终止条件和对于子单位的操作,此处终止条件就是(当前节点是否为空 || 当前节点的next是否为空),即分到只有一个节点或传入参数为空的情况;子单元的操作就是对其进行一次中点断链切分为两部分,然后对两部分进行合并操作。断链是在链表中点断链(对于中点的定义为:奇数个节点就在len/2处,偶数个节点在len/2 - 1处),寻找中点的过程用到了快慢指针;合并操作类似于合并两个原本有序的链表要求合并后的链表依然有序,这一操作思路也很简单的。

对于迭代法来说,关键在于把握住循环的终止条件,以及在每一intv轮合并时,找好h1和h2的位置,需要注意如果h2为NULL那么可以直接结束本次merge,之后就是比较多的细节要注意。

代码:

法一:

// 对链表进行自顶向下的归并排序(能通过,但不满足题目对空间复杂度的要求)
ListNode* sortList(ListNode* head) {if (head == NULL || head->next == NULL) return head;ListNode *fast, *slow;slow = head;fast = head->next;while (fast != NULL && fast->next != NULL) {slow = slow->next;fast = fast->next->next;}ListNode *temp = slow->next;slow->next = NULL;ListNode *left = sortList(head);ListNode *right = sortList(temp);// 合并left和right两个有序链表ListNode* new_head = (ListNode *)malloc(sizeof(ListNode));ListNode* p = new_head;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;}}p->next = (left == NULL) ? (right) : (left);return new_head->next;
}

法二:

// 自底向上规定排序 (迭代)
ListNode* sortList(ListNode* head) {if (head == NULL || head->next == NULL) return head;int len = 0, intv = 1;ListNode* p = head;while (p != NULL) {len++;p = p->next;}ListNode* new_head = (ListNode*)malloc(sizeof(ListNode));new_head->next = head;while (intv < len) {ListNode* pre = new_head;ListNode* h = new_head->next;while (h != NULL) {ListNode *h1 = h; // 第一部分的头int i = intv;ListNode *h2 = h1;while (h2 != NULL && i != 0) {h2 = h2->next; // 第二部分的头-- i;}if (i != 0) { // 还没找到h2 就走到头了 说明没有h2了,无须merge了break;}// 获取h1、h2部分的长度(h1不用再算了,因为如果h2存在那么h1肯定是完整的intv长度int c1 = intv;ListNode* travelH2 = h2;i = intv;while (travelH2 != NULL && i != 0) {travelH2 = travelH2->next;-- i;}h = travelH2; // h指向h2的末尾的下一个元素 即下两单位合并的开始部分int c2 = intv - i;// merge h1和h2部分while (c1 != 0 && c2 != 0) {if (h1->val < h2->val) {pre->next = h1;h1 = h1->next;--c1;}else {pre->next = h2;h2 = h2->next;--c2;}pre = pre->next;}if (c1 == 0) pre->next = h2;else pre->next = h1;while (c1 > 0 || c2 > 0) {pre = pre->next;--c1;--c2;}pre->next = h;}intv *= 2;}return new_head->next;
}

Leetcode-148-排序链表(递归+迭代)相关推荐

  1. 链表排序---迭代版本归并算法 + [leetcode]148. 排序链表

    前言: 对于链表来说,排序首选应该是归并算法 维基百科上有归并算法的迭代版本和递归版本 基于数组实现的. https://zh.wikipedia.org/wiki/%E5%BD%92%E5%B9%B ...

  2. 【编程4】插入排序+快速排序+LeetCode.148(排序链表)

    文章目录 一.排序链表 1.题目描述--LeetCode.148 2.分析 (1)一般的快排 (2)解题思路 3.实现 二.排序算法 三.插入排序 1.基本思想 (1)过程概述 (2)具体算法描述: ...

  3. Leetcode 148. 排序链表 解题思路及C++实现

    解题思路: 对链表进行归并排序,使用 fast 和 slow 两个指针,遍历一次链表,就能将链表切分为两半,然后使用归并排序的方法. /*** Definition for singly-linked ...

  4. LeetCode —— 148. 排序链表(Python)

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

  5. 83. Leetcode 148. 排序链表 (排序)

    给你链表的头结点 head ,请将其按 升序 排列并返回 排序后的链表 .示例 1:输入:head = [4,2,1,3] 输出:[1,2,3,4] 示例 2:输入:head = [-1,5,3,4, ...

  6. LeetCode 148. 排序链表(归并排序、快速排序)

    文章目录 1. 题目 2. 解题 2.1 归并排序 2.2 快速排序 1. 题目 在 O(n log n) 时间复杂度和常数级空间复杂度下,对链表进行排序. 示例 1:输入: 4->2-> ...

  7. leetcode 148. 排序链表(归并排序)

    给你链表的头结点 head ,请将其按 升序 排列并返回 排序后的链表 . 进阶: 你可以在 O(n log n) 时间复杂度和常数级空间复杂度下,对链表进行排序吗? 示例 1: 输入:head = ...

  8. 【LeetCode】【HOT】148. 排序链表(归并排序)

    [LeetCode][HOT]148. 排序链表 文章目录 [LeetCode][HOT]148. 排序链表 package hot;import java.util.Arrays;class Lis ...

  9. LeetCode Algorithm 148. 排序链表

    148. 排序链表 Ideas 链表结构的经典题目. 不过我不想用经典方法做,哎,就是皮. 我把链表元素都拷贝到数组中,然后对数组排序,之后再把排完序之后的值赋回去. 骚的一批. Code Pytho ...

  10. 2095. 删除链表的中间节点、19. 删除链表的倒数第 N 个结点、148. 排序链表

    LeetCode题解 1.2095. 删除链表的中间节点 2. 删除链表的倒数第 N 个结点 3.排序链表 1.2095. 删除链表的中间节点 题目描述: ➡️挑战链接⬅️ 分析: 首先题目要求我们删 ...

最新文章

  1. Windows窗体的所有菜单
  2. 计算字符串t在字符串s中出现的次数(KMP)
  3. haproxy调度web案例
  4. Game with modulo
  5. linux下的git 编辑器,vim - 如何让Git使用我选择的编辑器进行提交?
  6. python递归函数入门教程_Python递归函数
  7. 贺利坚老师汇编课程32笔记:处理字符串——大小写转换通过与和或运算加减20H
  8. 我们的年代《音乐天堂》经典回顾
  9. Atitit. 软件GUI按钮与仪表盘--web服务器区--获取apache配置文件路径 linux and apache的启动、停止、重启
  10. Win10值得推荐的软件,提升效率和桌面美观
  11. 从技术原理洞悉摄像头破解及防范
  12. 灵活使用CSS内联样式
  13. 计算机二级成绩划分标准,计算机二级成绩划分标准
  14. 《Real-Time Rendering》第四版学习笔记——Chapter 9 Physically Based Shading(一)
  15. Ubuntu16_18建立返回桌面、显示桌面的快捷图标的特殊方法
  16. 【数据结构与算法分析】第一章、第二章总结
  17. 一文看懂半监督学习(Semi-supervised Learning)和自监督学习(Self-Supervised Learning)
  18. codeforces1718 A1.Burenka and Traditions (easy version)
  19. Kibana KQL查询语法
  20. STM32F05x移植GD32F1x0注意事项

热门文章

  1. 求证:为什么当x趋近于0时,(sinx)/x的极限等于1
  2. 电脑族每天宜喝四杯茶
  3. 制作OTA U盘升级包
  4. python之读取文本操作
  5. 最大子段和动态规划_动态规划解最大子段和问题
  6. plsql怎么导出几十w的数据到csv_Greenplum数据库使用总结(干货满满)初级使用
  7. Python判断字符类型
  8. python 文本框内容变化_当文本框中的文本发生变化时,动态读取文本输入中的文本?...
  9. 外部接口需求怎么写_怎么写财务工作报告?送你16套高逼格财务工作报告范文PPT模板,满足不同行业会计需求!...
  10. layui的表单控件的input文本框赋值