【算法训练-链表】合并两个有序链表、合并K个有序链表

废话不多说,喊一句号子鼓励自己:程序员永不失业,程序员走向架构!首先,链表对应的数据结构在这篇Blog中:【基本数据结构 一】线性数据结构:链表,基于对基础知识的理解来进行题目解答。本篇Blog的主题是合并有序链表,近半年考察还是比较多的
在这里插入图片描述

合并两个有序链表

先来个基础版,合并两个已排序的链表

题干

在这里插入图片描述

输入:
{1,3,5},{2,4,6}返回值:
{1,2,3,4,5,6}
输入:
{},{}返回值:
{}
输入:
{-1,2,4},{1,3,4}返回值:
{-1,1,2,3,4,4}

解题思路

整体目标就是在两个链表中选节点来构建新链表

  1. 设置result为哨兵结点,放置于新链表之前,最后返回的就是dummy.next
  2. 设置cur为当前节点,从dummy开始,当两个链表都非空时进入循环,令新链表的下一个节点cur.next为val更小的节点,相应的链表节点后移一位,每次循环记得cur也要后移一位
  3. 如果循环结束后还有链表非空,cur指向非空链表,返回dummy.next

如下图所示:
在这里插入图片描述

解题代码

Java实现

import java.util.*;/** public class ListNode {*   int val;*   ListNode next = null;*   public ListNode(int val) {*     this.val = val;*   }* }*/public class Solution {/*** 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可*** @param pHead1 ListNode类* @param pHead2 ListNode类* @return ListNode类*/public ListNode Merge (ListNode pHead1, ListNode pHead2) {// 1 如果其中一个为空列表,直接返回另一个if (pHead1 == null && pHead2 == null) {return null;}if (pHead1 == null) {return pHead2;}if (pHead2 == null) {return pHead1;}// 2 定义哨兵节点用来返回最终链表,cur用来检索两个链表的较小值节点ListNode dummy = new ListNode(-1);ListNode cur = dummy;while (pHead1 != null && pHead2 != null) {if (pHead1.val <= pHead2.val) {cur.next = pHead1;pHead1 = pHead1.next;} else {cur.next = pHead2;pHead2 = pHead2.next;}cur = cur.next;}// 3 一个链表空后,直接将另一个链表剩余部分拼接if (pHead1 == null) {cur.next = pHead2;}if (pHead2 == null) {cur.next = pHead1;}return dummy.next;}
}

时间复杂度O(N+M):M N分别表示pHead1, pHead2的长度; 空间复杂度O(1):常数级空间

合并K个有序链表

OK,难度升级,两个变成K个有序链表进行合并

题干

在这里插入图片描述

输入:
[{1,2,3},{4,5,6,7}]返回值:
{1,2,3,4,5,6,7}
输入:
[{1,2},{1,4,5},{6}]返回值:
{1,1,2,4,5,6}

解题思路

归并排序是什么?简单来说就是将一个数组每次划分成等长的两部分,对两部分进行排序即是子问题。对子问题继续划分,直到子问题只有1个元素。还原的时候呢,将每个子问题和它相邻的另一个子问题利用上述双指针的方式,1个与1个合并成2个,2个与2个合并成4个,因为这每个单独的子问题合并好的都是有序的,直到合并成原本长度的数组。

对于这k个链表,就相当于上述合并阶段的k个子问题,需要划分为链表数量更少的子问题,直到每一组合并时是两两合并,然后继续往上合并,这个过程基于递归:

  • 终止条件: 划分的时候直到左右区间相等或左边大于右边。
  • 返回值: 每级返回已经合并好的子问题链表。
  • 本级任务: 对半划分,将划分后的子问题合并成新的链表。

具体做法:

  1. 步骤一:从链表数组的首和尾开始,每次划分从中间开始划分,划分成两半,得到左边n/2个链表和右边n/2个链表
  2. 步骤二:继续不断递归划分,直到每部分链表数为1.
  3. 步骤三:将划分好的相邻两部分链表,按照两个有序链表合并的方式合并,合并好的两部分继续往上合并,直到最终合并成一个链表。

如下图所示,先进行合并链表划分
在这里插入图片描述
划分完子问题,子问题处理完返回到上一层级
在这里插入图片描述

解题代码

Java实现代码

import java.util.*;/** public class ListNode {*   int val;*   ListNode next = null;*   public ListNode(int val) {*     this.val = val;*   }* }*/public class Solution {/*** 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可*** @param lists ListNode类ArrayList* @return ListNode类*/public ListNode mergeKLists (ArrayList<ListNode> lists) {return divideMerge(lists, 0, lists.size() - 1);}private ListNode divideMerge(ArrayList<ListNode> lists, int left, int right) {if (left > right) {return null;}// 终止条件,拿到了单独的链表if (left == right) {return lists.get(left);}int mid = (left + right) / 2;// 对两个相邻链表进行合并return merge(divideMerge(lists, left, mid), divideMerge(lists, mid + 1, right));}private ListNode merge(ListNode pHead1, ListNode pHead2) {// 1 链表非空判断if (pHead1 == null && pHead2 == null) {return null;}if (pHead1 == null) {return pHead2;}if (pHead2 == null) {return pHead1;}// 2 定义哨兵节点和最终返回链表ListNode dummy = new ListNode(-1);ListNode cur = dummy;while (pHead1 != null && pHead2 != null) {if (pHead1.val <= pHead2.val) {cur.next = pHead1;pHead1 = pHead1.next;} else {cur.next = pHead2;pHead2 = pHead2.next;}cur = cur.next;}// 3 如果一个链表空了,直接挂载另一个链表剩余节点if (pHead1 == null) {cur.next = pHead2;}if (pHead2 == null) {cur.next = pHead1;}return dummy.next;}
}

时间复杂度:O(nlogk),其中n为所有链表的总节点数,分治为二叉树型递归,最坏情况下二叉树每层合并都是O(n)个节点,而分治次数为:O(logk),所以总的时间复杂度就是O(nlogk)

空间复杂度:最坏情况下合并O(logk),所以递归栈的深度为O(logk)

拓展:递归和分治的区别

递归(Recursion)和分治(Divide and Conquer)是两种解决问题的方法,它们有一些相似之处,但也存在一些关键的区别。

递归(Recursion)
递归是一种问题解决方法,其中函数在其执行过程中调用自身来解决更小规模的子问题,直到达到基本情况,然后逐层返回结果以构建原始问题的解。递归的核心思想是将一个大问题划分为与原问题结构相同但规模更小的子问题,然后通过逐步解决这些子问题来解决原始问题。

分治(Divide and Conquer)
分治是一种将问题分解为多个相互独立的子问题,然后解决这些子问题并将它们的解合并以得到原始问题解的方法。分治的核心思想是将一个大问题划分为多个独立的子问题,这些子问题可以并行地解决,然后将它们的解合并起来以得到原问题的解。

关键区别:

  1. 目标

    • 递归的目标是通过将问题分解为与原问题结构相同但规模更小的子问题,然后逐层解决这些子问题来得到原问题的解。
    • 分治的目标是将问题分解为多个相互独立的子问题,然后并行地解决这些子问题,并将它们的解合并以得到原问题的解。
  2. 子问题之间的关系

    • 递归中,子问题之间的关系通常是相同结构的,但规模不同。
    • 分治中,子问题通常是相互独立的,没有交叉。
  3. 解决方式

    • 递归解决问题时,通常需要考虑如何将问题分解为更小的子问题,然后将这些子问题的解组合起来。
    • 分治解决问题时,通常需要考虑如何将问题分解为独立的子问题,然后并行地解决这些子问题,最后将它们的解合并起来。
  4. 合并过程

    • 递归中,解决子问题的过程是逐层递归地调用函数,然后逐层返回结果。
    • 分治中,解决子问题的过程可以并行地进行,然后将子问题的解合并。

总的来说,递归和分治都是将复杂问题分解为更小的部分来解决的方法,但它们的关注点和执行方式有所不同。在实际应用中,有时候递归和分治可以结合使用,例如在分治算法的子问题解决过程中使用递归。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://xiahunao.cn/news/1619694.html

如若内容造成侵权/违法违规/事实不符,请联系瞎胡闹网进行投诉反馈,一经查实,立即删除!

相关文章

alias命令手册

alias&#xff1a;查看和定义别名 功能描述 alias命令用来设置指令的别名。使用alias时&#xff0c;用户可以使用单引号 ‘ ‘ 将原来的命令引起来&#xff0c;防止特殊字符导致错误。 alias命令的作用只局限于该次登入的操作。若要每次登入都能够使用这些命令别名&#xff0c;…

Ubuntu学习之alias命令

Ubuntu学习之alias命令 1.1 alias功能介绍 当我们经常需要在命令窗键入复杂冗长的命令时&#xff0c;alias就派上用场啦。alias允许用户为命令创建简单的名称或缩写&#xff0c;哪怕这个缩写只有一个字符。即为指令设置别名。 1.2 alias语法 语法&#xff1a;alias [name”va…

linux alias命令路径,Linux alias命令

本文概述 Linux的” alias”命令将shell中的一个字符串替换为另一个字符串。这是一个shell内置命令。它将复杂的命令转换为更简单的命令, 换句话说, 通过将其替换为更简单的命令来创建快捷方式。 在命令行中使用”alias”会创建一个临时的”alias”。临时alias仅在退出外壳程序…

git alias

git alias 其实之前就用过一些 alias&#xff0c;比如说 git reflog show 就是 git log -g --abbrev-commit --prettyoneline 的 alias&#xff0c;一般 alias 可以存储到 git 的 config 文件&#xff0c;repo 等级的在 .git 下&#xff0c;global 的一般在 ~/.gitconfig 或者…

【ubuntu】alias命令

目录 1 alias的作用 2 语法 &#xff08;1&#xff09;简单命令 &#xff08;2&#xff09;多条命令 3 alias永久化 &#xff08;1&#xff09;启动vim编辑器 &#xff08;2&#xff09;进入编辑模式 &#xff08;3&#xff09;退出 &#xff08;4&#xff09;source使…

Elasticsearch:Index alias

现在让我们来谈谈 Elasticsearch 最简单和最有用的功能之一&#xff1a;别名 &#xff08;alias)。为了区分这里 alias 和文章 “Elasticsearch : alias 数据类型”&#xff0c;这里的别名&#xff08;alias&#xff09;指的是 index 的别名。 别名正是他们听起来的样子; 它们是…

Linux alias 的用法

Linux alias 的用法 作者: Sway 1. 啥是alias alias的英文意思是别名. 通俗来说 alias 的概念是让方便你写一段非常非常小的小程序 如 : sway:~$ alias alias lsls --colorauto这里的意思是当你输入 ls 的时候就等同输入 ls --colorauto 但是当我们切换用户的时候 alias …

Nginx中alias与root的区别

目录&#xff1a; 一、区别二、举例说明1三、举例说明2 一、区别 Nginx指定文件路径有两种方式root和alias&#xff0c;这两者的用法区别在于对URI的处理方法不同。 二、举例说明1 alias&#xff1a; location /i/{ alias /usr/local/nginx/html/admin/&#xff1b;} #若…

详解nginx的root与alias

文章目录 1. 结论2. 详解root2.1 基本用法2.2 location的最左匹配原则2.3 index2.4 nginx location解析url工作流程2.5 末尾/ 3. 详解alias3.1 基本用法 4. 特殊情况4.1 alias指定文件4.2 root指定文件 nginx版本: 1.18.0 1. 结论 location命中后 如果是root&#xff0c;会把…

Linux命令之alias

在Linux中&#xff0c;alias命令的功能是设置命令的别名&#xff0c;用以简写命令&#xff0c;提高操作效率。根据参数的不同&#xff0c;该命令可查看已设定的别名&#xff0c;或为命令设置新的别名。对于用户自定义别名&#xff0c;仅当前登录期内有效&#xff1b;也可修改配…

Linux之alias命令

回复【1001】获取 linux常用命令速查手册 Linux alias命令用来设置指令的别名&#xff0c;对一些较长的命令进行简化。使用alias时&#xff0c;必须使用单引号将原来的命令包含&#xff0c;防止特殊字符导致错误。 命令格式 alias [-p] [name[value] ...] 命令功能 简化较长…

别名机制alias详解——一个让你少敲键盘的偷懒方式

别名机制alias——让你少敲键盘的偷懒方式 目录 别名机制alias——让你少敲键盘的偷懒方式样例环境1.从一个例子开始&#xff1a;2.别名机制alias&#xff1a;2.1 什么是alias&#xff1a;2.2 alias怎么用&#xff1a;2.3 alias的注意事项&#xff1a; 参考文献&#xff1a; 样…

Linux基础——别名(alias)

一、啥是别名? 别名&#xff08;alias&#xff09;是某个命令或者某一组命令的代称&#xff0c;和我们的小名或者外号一样&#xff0c;比如一些少数民族或者复姓的同学名字可能比较长&#xff0c;那我们一般不会每次都喊全名&#xff0c;而是用一个能特指他的另外一个名字称呼…

Linux——alias命令(设置命令别名)

Linux——alias命令&#xff08;设置命令别名&#xff09; alias 是shell内建命令&#xff08;即shell中自带的命令&#xff09;&#xff0c;它可以将常用的命令以及它的参数创建一个别名&#xff0c;来减少命令的输入量 我们常用的一些命令就是别名 eg&#xff1a;ls 、ll 1…

GIthub 无法访问使用Watt Toolkit加速

一、使用 Watt Toolkit Watt Toolkit 是一款加速软件&#xff0c;原名是 Steam&#xff0c;后来改名为 Watt Toolkit&#xff0c;其可以让原本无法访问的 Steam 游戏社区、 GitHub 、谷歌验证码等国内难以访问的网页正常访问。 三种下载方式&#xff1a; Watt Toolkit 官网下…

【JavaEE】Spring事务-@Transactional参数介绍-事务的隔离级别以及传播机制

【JavaEE】Spring事务&#xff08;2&#xff09; 文章目录 【JavaEE】Spring事务&#xff08;2&#xff09;1. Transactional 参数介绍1.1 value 和 transactionManager1.2 timeout1.3 readOnly1.4 后面四个1.5 isolation 与 propagation 2. Spring 事务隔离级别 - isolation2.…

房屋中介费怎么收取才合理?快看看别再花冤枉钱了

[摘要]本文讲述了什么是房屋中介&#xff0c;房屋中介费是如何收取的&#xff0c;房屋中介费的收取标准是什么。希望可以对即将用到房屋中介的网友们有所帮助。 买房的朋友都应该知道有房产中介这回事&#xff0c;甚至有的是通过房产中介的服务来买的房&#xff0c;当然&#x…

基于C#的房屋租赁管理系统设计与实现

目录 第一章 引言 3 第二章 系统分析与设计 4 2.1 需求分析 4 设计流程图&#xff1a; 4 2.2数据库概念结构设计 5 E-R图 5 2.3数据库的创建 6 管理员表&#xff1a; 6 房屋表&#xff1a; 7 用户信息表&#xff1a; 7 房屋租贷表&#xff1a; 7 财务报表&#xff1a; 7 收费标…

设计模式.中介者模式Mediator

定义 中介者模式(Mediator pattern) : 使用中介者模式来集中相关对象之间复杂的沟通和控制方式&#xff0c;使得这些对象不必相互明显引用。从而使它们可以较松散地耦合。当这些对象中的某些对象之间的相互作用发生改变时&#xff0c;不会立即影响到其他的一些对象之间的相互作…