☆打卡算法☆LeetCode 148. 排序链表 算法解析

简介: ☆打卡算法☆LeetCode 148. 排序链表 算法解析

一、题目

1、算法题目

“给定链表的头结点,返回按照升序排序的链表。”

2、题目描述

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

1702361596778.jpg

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

二、解题

1、思路分析

147题是实现链表的插入排序,时间复杂度是O(n2)。

这道题要求时间复杂度更低的排序算法,要求达到O(n log n)的时间复杂度。

可以实现O(n log n)的时间复杂度的排序算法有归并排序、堆排序和快速排序,其中最适合链表的排序算法是归并排序。

首先来了解一下什么是归并排序,归并排序是自顶向下直接合并的方式进行排序,具体过程如下:

  • 1、找到链表中点,以中点为界,将链表拆成两个子链表。
  • 2、对两个子链表分别排序。
  • 3、将两个排序后子链表合并,得到完成链表。

因为上述的过程是通过递归实现的,所以时间复杂度为O(n log n),空间复杂度为O(log n)。

2、代码实现

代码参考:

class Solution {
    public ListNode sortList(ListNode head) {
        return sortList(head, null);
    }
    public ListNode sortList(ListNode head, ListNode tail) {
        if (head == null) {
            return head;
        }
        if (head.next == tail) {
            head.next = null;
            return head;
        }
        ListNode slow = head, fast = head;
        while (fast != tail) {
            slow = slow.next;
            fast = fast.next;
            if (fast != tail) {
                fast = fast.next;
            }
        }
        ListNode mid = slow;
        ListNode list1 = sortList(head, mid);
        ListNode list2 = sortList(mid, tail);
        ListNode sorted = merge(list1, list2);
        return sorted;
    }
    public ListNode merge(ListNode head1, ListNode head2) {
        ListNode dummyHead = new ListNode(0);
        ListNode temp = dummyHead, temp1 = head1, temp2 = head2;
        while (temp1 != null && temp2 != null) {
            if (temp1.val <= temp2.val) {
                temp.next = temp1;
                temp1 = temp1.next;
            } else {
                temp.next = temp2;
                temp2 = temp2.next;
            }
            temp = temp.next;
        }
        if (temp1 != null) {
            temp.next = temp1;
        } else if (temp2 != null) {
            temp.next = temp2;
        }
        return dummyHead.next;
    }
}

1702361655726.jpg


3、时间复杂度

时间复杂度:O(n log n)

其中n是链表的长度。

空间复杂度:O(log n)

其中n是链表的长度,空间复杂度主要取决于递归调用的栈空间。

三、总结

通过递归实现链表的归并排序,主要分成两步。

第一步是分割成两个子链表。

可以使用快慢指针,快指针每次移动2步,慢指针每次移动1步,当快指针移动到链表末尾时,慢指针指向链表的节点就是链表的中点。

第二步是子链表递归分别排序。

设置两个指针分别指向两个链表头部,比较两个指针处节点值大小,由小到大加入合并到链表头部,指针交替前进,直到添加完两个链表。

相关文章
|
5月前
|
存储 人工智能 算法
从零掌握贪心算法Java版:LeetCode 10题实战解析(上)
在算法世界里,有一种思想如同生活中的"见好就收"——每次做出当前看来最优的选择,寄希望于通过局部最优达成全局最优。这种思想就是贪心算法,它以其简洁高效的特点,成为解决最优问题的利器。今天我们就来系统学习贪心算法的核心思想,并通过10道LeetCode经典题目实战演练,带你掌握这种"步步为营"的解题思维。
|
6月前
|
机器学习/深度学习 人工智能 搜索推荐
从零构建短视频推荐系统:双塔算法架构解析与代码实现
短视频推荐看似“读心”,实则依赖双塔推荐系统:用户塔与物品塔分别将行为与内容编码为向量,通过相似度匹配实现精准推送。本文解析其架构原理、技术实现与工程挑战,揭秘抖音等平台如何用AI抓住你的注意力。
1492 7
从零构建短视频推荐系统:双塔算法架构解析与代码实现
|
6月前
|
机器学习/深度学习 算法 安全
【无人机三维路径规划】基于非支配排序的鱼鹰优化算法NSOOA求解无人机三维路径规划研究(Matlab代码实现)
【无人机三维路径规划】基于非支配排序的鱼鹰优化算法NSOOA求解无人机三维路径规划研究(Matlab代码实现)
147 0
|
6月前
|
供应链 算法 Java
【柔性作业车间调度问题FJSP】基于非支配排序的多目标小龙虾优化算法求解柔性作业车间调度问题FJSP研究(Matlab代码实现)
【柔性作业车间调度问题FJSP】基于非支配排序的多目标小龙虾优化算法求解柔性作业车间调度问题FJSP研究(Matlab代码实现)
224 1
|
6月前
|
机器学习/深度学习 算法 安全
【无人机三维路径规划】基于非支配排序的鲸鱼优化算法NSWOA与多目标螳螂搜索算法MOMSA求解无人机三维路径规划研究(Matlab代码实现)
【无人机三维路径规划】基于非支配排序的鲸鱼优化算法NSWOA与多目标螳螂搜索算法MOMSA求解无人机三维路径规划研究(Matlab代码实现)
320 5
|
6月前
|
机器学习/深度学习 运维 算法
基于非支配排序遗传算法NSGAII的综合能源优化调度(Matlab代码实现)
基于非支配排序遗传算法NSGAII的综合能源优化调度(Matlab代码实现)
341 0
基于非支配排序遗传算法NSGAII的综合能源优化调度(Matlab代码实现)
|
6月前
|
机器学习/深度学习 算法 安全
【无人机三维路径规划】多目标螳螂搜索算法MOMSA与非支配排序的鲸鱼优化算法NSWOA求解无人机三维路径规划研究(Matlab代码实现)
【无人机三维路径规划】多目标螳螂搜索算法MOMSA与非支配排序的鲸鱼优化算法NSWOA求解无人机三维路径规划研究(Matlab代码实现)
233 0
|
6月前
|
机器学习/深度学习 存储 算法
动态规划算法深度解析:0-1背包问题
0-1背包问题是经典的组合优化问题,目标是在给定物品重量和价值及背包容量限制下,选取物品使得总价值最大化且每个物品仅能被选一次。该问题通常采用动态规划方法解决,通过构建二维状态表dp[i][j]记录前i个物品在容量j时的最大价值,利用状态转移方程避免重复计算子问题,从而高效求解最优解。
690 1
|
6月前
|
算法 搜索推荐 Java
贪心算法:部分背包问题深度解析
该Java代码基于贪心算法求解分数背包问题,通过按单位价值降序排序,优先装入高价值物品,并支持部分装入。核心包括冒泡排序优化、分阶段装入策略及精度控制,体现贪心选择性质,适用于可分割资源的最优化场景。
410 1
贪心算法:部分背包问题深度解析
|
6月前
|
存储 算法 搜索推荐
软考算法破壁战:从二分查找到堆排序,九大排序核心速通指南
专攻软考高频算法,深度解析二分查找、堆排序、快速排序核心技巧,对比九大排序算法,配套动画与真题,7天掌握45%分值模块。
272 1
软考算法破壁战:从二分查找到堆排序,九大排序核心速通指南