【链表专题】(2. 两数相加 23. 合并 K 个升序链表 25. K 个一组翻转链表)

文章目录

  • 2. 两数相加
  • 23. 合并 K 个升序链表
  • 25. K 个一组翻转链表


2. 两数相加

题目链接: leetcode2. 两数相加

在这里插入图片描述

class Solution {public ListNode addTwoNumbers(ListNode l1, ListNode l2) {ListNode cur1 = l1,cur2 = l2;ListNode newHead = new ListNode(0);ListNode prev = newHead;int t = 0;while(cur1 != null || cur2 != null || t != 0){if(cur1 != null){t += cur1.val;cur1 = cur1.next;}if(cur2 != null){t += cur2.val;cur2 = cur2.next;}prev.next = new ListNode(t%10);prev = prev.next;t /= 10;}return newHead.next;}
} 

addTwoNumbers该方法接收两个ListNode类型的参数l1和l2,表示两个非负整数的链表表示。方法的目的是将这两个链表表示的整数相加,并返回一个新的链表表示结果。

代码逻辑如下:

  1. 创建两个指针cur1和cur2,分别指向l1和l2的头部。
  2. 创建一个新的链表newHead,用于存储结果。
  3. 创建一个指针prev,指向newHead。
  4. 初始化一个变量t为0,用于存储进位值。
  5. 使用while循环,当cur1、cur2不为空或者t不等于0时,执行以下操作:
    • 如果cur1不为空,将cur1的值加到t上,并将cur1指向下一个节点。
    • 如果cur2不为空,将cur2的值加到t上,并将cur2指向下一个节点。
    • 创建一个新的节点,值为t对10取模的结果,并将其添加到prev后面。
    • 更新prev为新添加的节点。
    • 将t除以10,得到新的进位值。
  6. 返回newHead的下一个节点,即结果链表的头节点。

23. 合并 K 个升序链表

题目链接: leetcode23. 合并 K 个升序链表

在这里插入图片描述

解法一:优先级队列

题解代码:

class Solution {public ListNode mergeKLists(ListNode[] lists) {// 1.创建一个小根堆PriorityQueue<ListNode> heap = new PriorityQueue<>((v1,v2) -> v1.val - v2.val);// 2.把所有的头结点放进小根堆中for(ListNode head : lists){if(head != null){heap.offer(head);}}// 3.合并链表ListNode ret = new ListNode(0);ListNode prev = ret;while(!heap.isEmpty()){ListNode t = heap.poll();prev.next = t;prev = t;if(t.next != null) heap.offer(t.next);}return ret.next;}
}

下面这个代码创建了一个优先级队列(PriorityQueue),用于存储ListNode类型的对象。优先级队列的排序规则是按照ListNode对象的val属性值进行升序排列。

PriorityQueue<ListNode> heap = new PriorityQueue<>((v1,v2) -> v1.val - v2.val);

如果优先级队列的排序规则是按照ListNode对象的val属性值进行降序排列,代码如下:

PriorityQueue<ListNode> heap = new PriorityQueue<>((v1, v2) -> v2.val - v1.val);

下面这段代码它遍历一个名为lists的ListNode类型的列表。对于列表中的每个元素(这里称为head),如果该元素不为null,就将其添加到一个名为heap的优先级队列中。

解析:

  1. for(ListNode head : lists):这是一个增强型for循环,用于遍历名为lists的ListNode类型的列表。每次循环,都会将列表中的一个元素赋值给变量head。
  2. if(head != null):这是一个条件判断语句,用于检查变量head是否为null。如果head不为null,则执行大括号内的代码。
  3. heap.offer(head):这是将变量head添加到名为heap的优先级队列中。offer()方法是Java的Queue接口中的方法,用于在队列的尾部插入一个元素。

代码:

for(ListNode head : lists){if(head != null){heap.offer(head);}
}

下面这段代码的主要功能是将一个链表(由ListNode节点组成)从堆中取出并重新组合。

首先,创建一个新的ListNode节点ret,并将其值设为0。然后,创建一个prev指针,指向ret。

然后,进入一个while循环,条件是堆不为空。在循环中,首先从堆中取出一个元素(即链表的一个节点),然后将prev的下一个节点设置为这个取出的元素。然后,将prev移动到这个新添加的节点上。

如果取出的节点的下一个节点不为空,那么将这个下一个节点添加到堆中。这样,就可以保证链表的顺序不变。

这个过程会一直进行,直到堆为空。最后,返回ret.next,即重新组合后的链表的头节点。

// 3.合并链表ListNode ret = new ListNode(0);ListNode prev = ret;while(!heap.isEmpty()){ListNode t = heap.poll();prev.next = t;prev = t;if(t.next != null) heap.offer(t.next);}

解法二:分治 - 递归

class Solution {public ListNode mergeKLists(ListNode[] lists) {return merge(lists, 0, lists.length - 1);}public ListNode merge(ListNode[] lists, int left, int right) {if (left > right) return null;if (left == right) return lists[left];// 1. 先平分数组int mid = (left + right) / 2;// [left, mid] [mid + 1, right]// 2. 递归处理左右两部分ListNode l1 = merge(lists, left, mid);ListNode l2 = merge(lists, mid + 1, right);// 3. 合并两个有序链表return mergeTwoList(l1, l2);}public ListNode mergeTwoList(ListNode l1, ListNode l2) {if (l1 == null) return l2;if (l2 == null) return l1;// 合并两个有序链表ListNode head = new ListNode(0);ListNode cur1 = l1, cur2 = l2, prev = head;while (cur1 != null && cur2 != null) {if (cur1.val <= cur2.val) {prev.next = cur1;prev = cur1;cur1 = cur1.next;} else {prev.next = cur2;prev = cur2;cur2 = cur2.next;}}if (cur1 != null) {prev.next = cur1;}if (cur2 != null) {prev.next = cur2;}return head.next;}
}

这段代码实现了一个名为Solution的类,其中包含了三个方法:mergeKListsmergemergeTwoList

  • mergeKLists方法是整个算法的入口点,它接受一个ListNode数组作为输入,表示要合并的K个有序链表。该方法调用了merge方法来执行合并操作,并返回合并后的链表头节点。

  • merge方法是一个递归方法,用于将给定范围内的链表进行合并。它首先判断左边界是否大于右边界,如果是,则返回空值(表示没有需要合并的链表)。如果左边界等于右边界,则直接返回该链表。否则,它将范围分为两半,分别递归地调用merge方法来合并左右两部分,并将结果传递给mergeTwoList方法进行最终的合并操作。

  • mergeTwoList方法用于合并两个有序链表。它首先判断其中一个链表是否为空,如果是,则直接返回另一个链表。然后,它创建一个新的头节点head和一个指针prev,用于构建合并后的链表。通过比较两个链表当前节点的值,选择较小的节点连接到新链表中,并更新指针位置。最后,如果有一个链表还有剩余节点,将其连接到新链表的末尾。最终返回新链表的头节点。

这段代码使用了分治的思想,通过递归地将问题划分为更小的子问题来解决。在每一步中,它将链表数组分成两半,并递归地合并这两部分。最后,通过mergeTwoList方法将两个有序链表合并成一个有序链表。

25. K 个一组翻转链表

题目链接: leetcode25. K 个一组翻转链表

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

解法:模拟

  1. 先求出需要逆序多少组:n
  2. 重复n次,长度为k的链表的逆序即可(头插法)

在这里插入图片描述

class Solution {public ListNode reverseKGroup(ListNode head, int k) {// 1.先求出需要逆序多少组int n = 0;ListNode cur = head;while(cur != null){cur = cur.next;n++;}n /= k;// 2.重复n次 :长度为k的链表的逆序ListNode newHead = new ListNode(0);ListNode prev = newHead;cur = head;for(int i = 0; i < n; i++){ListNode tmp = cur;for(int j = 0; j < k; j++){// 头插ListNode next = cur.next;cur.next = prev.next;prev.next = cur;cur = next;}prev = tmp;}// 把后面不需要逆序的连接上prev.next = cur;return newHead.next;}
}

reverseKGroup该方法接收两个参数:一个ListNode类型的head和一个整数k。这个方法的目的是将链表中的节点按照k个一组进行逆序排列。

  1. 首先,通过遍历链表,计算出需要逆序的组数n。
  2. 然后,重复n次以下操作:长度为k的链表的逆序。在这个过程中,使用头插法将当前节点插入到新链表的头部。
  3. 最后,将剩余不需要逆序的节点连接到新链表的尾部,并返回新链表的头节点。
// 2.重复n次 :长度为k的链表的逆序ListNode newHead = new ListNode(0);ListNode prev = newHead;cur = head;for(int i = 0; i < n; i++){ListNode tmp = cur;for(int j = 0; j < k; j++){// 头插ListNode next = cur.next;cur.next = prev.next;prev.next = cur;cur = next;}prev = tmp;}

这段代码的功能是将一个链表按照长度为k的子链表进行逆序排列。具体实现如下:

  1. 创建一个新链表newHead,用于存储逆序后的结果。
  2. 使用两个指针prev和cur,分别指向新链表的尾部和原链表的头部。
  3. 使用一个外层循环,重复n次,其中n为需要逆序的组数。
  4. 在外层循环中,使用一个内层循环,重复k次,将当前子链表逆序插入到新链表中。
  5. 在内层循环中,首先记录当前节点的下一个节点next。
  6. 然后,将当前节点的next指针指向prev的下一个节点,即将当前节点插入到新链表的头部。
  7. 更新prev的next指针为当前节点,即prev指向当前节点。
  8. 更新cur指针为next,即移动到下一个节点。
  9. 在外层循环结束后,将剩余不需要逆序的节点连接到新链表的尾部。
  10. 最后,返回新链表的头节点newHead.next。

在这段代码中,"把不需要逆序的连接上"的步骤没有使用循环的原因是因为在之前的步骤中已经完成了所有需要逆序的分组操作。具体来说,由于我们已经按照每k个节点为一组进行了逆序排列,当我们执行到最后一组的时候,这组后面的节点都是不需要再逆序的。

在for循环中,我们重复n次逆序长度为k的链表的操作。每次循环,都会处理一个长度为k的子链表,然后将其逆序连接到之前已经逆序好的链表后面。变量prev在这里扮演了一个指针的角色,它始终指向当前逆序列表的尾部(即已逆序部分的最后一个节点)。

当for循环结束时,cur指针将会指向最后一个逆序好的子链表的下一个节点,也就是第一个不需要逆序的节点。因此,我们可以直接通过赋值prev.next = cur;将不需要逆序的部分连接到已逆序的链表后面。这一步不需要循环,因为剩下的节点已经是正确顺序的,并且只需要一次性地将它们全部连在一起。

总结一下,不使用循环的原因是因为:

  1. 在逆序的for循环中,我们处理了所有需要逆序的分组。
  2. 最后剩下的所有节点都不需要逆序,它们已经在正确的顺序中。
  3. 只需一步就能将这些剩余节点链接到已逆序的链表尾部。

所以,这里的设计是先通过循环处理所有需要特殊处理的节点,然后通过一次简单的赋值操作完成剩余节点的连接,从而避免了不必要的循环。

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

STM32的简介

内存 一般MCU包含的存储空间有FLASH和RAM,&#xff08;RAM和flash又有片上和片外的区别&#xff0c;片上表示mcu自带的&#xff0c;已经封装在MCU内部的&#xff0c;片外表示外挂的&#xff0c;当项目中需要做一些复杂的应用&#xff0c;会存在资源不足的情况&#xff0c;这时…

MIT最新研究成果 机器人能够从错误中纠偏 无需编程介入和重复演示

目前科学家们正在努力让机器人变得更加智能&#xff0c;教会他们完成诸如擦拭桌面&#xff0c;端盘子等复杂技能。以往机器人要在非结构化环境执行这样的任务&#xff0c;需要依靠固定编程进行&#xff0c;缺乏场景通用性&#xff0c;而现在机器人的学习过程主要在于模仿&#…

LeetCode 双指针专题

11.盛最多水的容器 给定一个长度为 n 的整数数组 height 。有 n 条垂线&#xff0c;第 i 条线的两个端点是 (i, 0) 和 (i, height[i]) 。 找出其中的两条线&#xff0c;使得它们与 x 轴共同构成的容器可以容纳最多的水。 返回容器可以储存的最大水量。 说明&#xff1a;你不…

数据结构——lesson13排序之计数排序

&#x1f49e;&#x1f49e; 前言 hello hello~ &#xff0c;这里是大耳朵土土垚~&#x1f496;&#x1f496; &#xff0c;欢迎大家点赞&#x1f973;&#x1f973;关注&#x1f4a5;&#x1f4a5;收藏&#x1f339;&#x1f339;&#x1f339; &#x1f4a5;个人主页&#x…

基于单片机锂电池电量检测数码管显示系统设计

**单片机设计介绍&#xff0c;基于单片机锂电池电量检测数码管显示系统设计 文章目录 一 概要二、功能设计设计思路 三、 软件设计原理图 五、 程序六、 文章目录 一 概要 基于单片机锂电池电量检测数码管显示系统设计的主要目标是实时、准确地检测锂电池的电量&#xff0c;并…

【python】常用函数汇总(持续更新……)

文章目录 【numpy.exp()】返回e的幂次方&#xff0c;e是一个常数为2.71828【np.dot()】矩阵相乘【np.linalg.inv()】矩阵求逆 【numpy.exp()】返回e的幂次方&#xff0c;e是一个常数为2.71828 举例&#xff1a;numpy.exp() 【np.dot()】矩阵相乘 【要点】 1、前者的列数后者…

浅谈Spring体系的理解

浅谈Spring知识体系 Spring Framework架构图Spring家族技术生态全景图XMind汇总 本文不涉及细节&#xff0c;主要回答两个问题&#xff1a; Spring家族技术生态全景图有哪些Spring Framework架构下每个模块有哪些东西&#xff0c;以及部分模块之间的关联关系 Spring Framework架…

iOS - Runtime - Class的结构

文章目录 iOS - Runtime - Class的结构前言1. Class的结构1.1 Class的结构1.1.1 objc_class1.1.2 class_rw_t1.1.3 class_ro_t 1.2 class_rw_t和class_ro_t的区别1.3 class_rw_t和class_ro_t的关系1.3.1 分析关系1.3.2 原因 1.4 method_t1.4.1 Type Encoding1.4.2 types说明1.4…

AJAX-项目优化(目录、基地址、token、请求拦截器)

目录管理 基地址存储 在utils/request.js配置axios请求基地址 作用&#xff1a;提取公共前缀地址&#xff0c;配置后axios请求时都会baseURLurl 填写API的公共前缀后&#xff0c;将js文件导入到html文件中 <script src"../../utils/request.js"></script&…

深度学习算法概念介绍

前言 深度学习算法是一类基于人工神经网络的机器学习方法&#xff0c;其核心思想是通过多层次的非线性变换&#xff0c;从数据中学习表示层次特征&#xff0c;从而实现对复杂模式的建模和学习。深度学习算法在图像识别、语音识别、自然语言处理等领域取得了巨大的成功&#xf…

STM32的IAP技术,BootLoader

来源 三种下载方式&#xff1a; 1、ICP&#xff1a;ST-Link, 2、ISP: FlyMcu, 3、IAP IAP简介 IAP技术的核心在于BootLoader程序的设计&#xff0c;这段程序预先烧录在单片机中&#xff0c;正常的APP程序可以使用BootLoader程序中的IAP功能写入&#xff0c;也可以两部分代码一…

docker使用教程

寒假用了docker 2个月没用 结果还重新安装docker 忘了怎么用 为了免得以后忘写下下面内容 # If you dont have a docker installed, youll need to install docker curl -s https://get.docker.com/ | sh # Use pip to install docker-compose pip install docker-compose…

排序第五篇 归并排序

一 简介 归并排序(Merge Sort) 的基本思想是&#xff1a; 首先将待排序文件看成 n n n 个长度为1的有序子文件&#xff0c; 把这些子文件两两归并&#xff0c; 得到 n 2 \frac{n}{2} 2n​ 个长度为 2 的有序子文件&#xff1b; 然后再把这 n 2 \frac{n}{2} 2n​ 个有序的子…

EI期刊和EI会议有哪些不同?别再傻傻分不清

EI工程索引是综合性检索机构&#xff0c;是三个著名学术检索系统之一&#xff0c;EI工程索引也分为EI期刊和EI会议&#xff0c;那么两者有哪些不同&#xff1f;作者又该如何选&#xff1f;本文系统分享一下相关的知识&#xff0c;仅供学术人员参考&#xff1a; 第一、文章质量不…

2014年认证杯SPSSPRO杯数学建模A题(第二阶段)轮胎的花纹全过程文档及程序

2014年认证杯SPSSPRO杯数学建模 A题 轮胎的花纹 原题再现&#xff1a; 轮胎被广泛使用在多种陆地交通工具上。根据性能的需要&#xff0c;轮胎表面常会加工出不同形状的花纹。在设计轮胎时&#xff0c;往往要针对其使用环境&#xff0c;设计出相应的花纹形状。   第二阶段问…

南京观海微电子---Vitis HLS的工作机制——Vitis HLS教程

1. 前言 Vitis HLS&#xff08;原VivadoHLS&#xff09;是一个高级综合工具。用户可以通过该工具直接将C、 C编写的函数翻译成HDL硬件描述语言&#xff0c;最终再映射成FPGA内部的LUT、DSP资源以及RAM资源等。 用户通过Vitis HLS&#xff0c;使用C/C代码来开发RTL IP核&#x…

前端优化gzip

gzip是GNUzip的缩写&#xff0c;是一种文件的压缩格式&#xff08;也可以说是若干种文件压缩程序&#xff09;&#xff0c;类似的压缩格式还有compress&#xff08;webpack&#xff09;&#xff0c;deflate等 主要用于组件的压缩 压缩的话主要分为两种&#xff0c; 服务器在…

TCP网络协议栈和Posix网络部分API总结

文章目录 Posix网络部分API综述TCP协议栈通信过程TCP三次握手和四次挥手&#xff08;看下图&#xff09;三次握手常见问题&#xff1f;为什么是三次握手而不是两次&#xff1f;三次握手和哪些函数有关&#xff1f;TCP的生命周期是从什么时候开始的&#xff1f; 四次挥手通信状态…

强化基础-Java-泛型基础

什么是泛型&#xff1f; 泛型其实就参数化类型&#xff0c;也就是说这个类型类似一个变量是可变的。 为什么会有泛型&#xff1f; 在没有泛型之前&#xff0c;java中是通过Object来实现泛型的功能。但是这样做有下面两个缺陷&#xff1a; 1 获取值的时候必须进行强转 2 没有…

005 高并发内存池_CentralCache设计

​&#x1f308;个人主页&#xff1a;Fan_558 &#x1f525; 系列专栏&#xff1a;高并发内存池 &#x1f339;关注我&#x1f4aa;&#x1f3fb;带你学更多知识 文章目录 前言本文重点一、构建CentralCache结构二、运用慢开始反馈调节算法三、完成向CentralCache中心缓存申请四…