算法: 链表题目练习

文章目录

  • 链表题目练习
    • 两数相加
    • 两两交换链表中的节点
    • 重排链表
    • 合并 K 个升序链表
    • K 个一组翻转链表
  • 总结


链表题目练习

两数相加

在这里插入图片描述
坑:

  • 两个链表都遍历完后,可能需要进位.
    class Solution {public ListNode addTwoNumbers(ListNode l1, ListNode l2) {ListNode cur1 = l1;ListNode cur2 = l2;ListNode head = new ListNode(0);ListNode tail = head;int sum = 0;while (cur1 != null || cur2 != null) {ListNode newNode = new ListNode();tail.next = newNode;tail = newNode;if (cur1 != null) {sum += cur1.val;cur1 = cur1.next;}if (cur2 != null) {sum += cur2.val;cur2 = cur2.next;}if (sum >= 10) {newNode.val = sum % 10;sum = 1;} else {newNode.val = sum;sum = 0;}}// 遍历完两个链表 处理一下进位if (sum != 0) {ListNode newNode = new ListNode(sum);tail.next = newNode;}return head.next;}}

题解代码:

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

两两交换链表中的节点

在这里插入图片描述
简简单单,一遍过~

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

    class Solution {public ListNode swapPairs(ListNode head) {ListNode virtualHead = new ListNode();virtualHead.next = head;ListNode cur = head, prev = virtualHead;while (cur != null && cur.next != null) {ListNode next = cur.next;prev.next = next;cur.next = next.next;next.next = cur;prev = cur;cur = cur.next;}return virtualHead.next;}}

重排链表

在这里插入图片描述
没想出来,看题解思路懂哩~

分成三步走:

  1. 找到原链表的中间节点(可以使用快慢指针解决)。
  2. 将原链表的右半部分翻转。
  3. 将原链表的两端合并。
    • 因为两链表的长度相差不超过 1,所以可以直接合并~

磕磕绊绊总算是写出来了~
看似是一道题,其实是三道题~

在合并两个链表时卡了一下.

坑:

  • 前面有指针指向 中间节点 ,链表翻转后指针的指向大概是这样的
    在这里插入图片描述
class Solution {public void reorderList(ListNode head) {// 寻找中间节点ListNode fast = head, slow = head;while (fast != null && fast.next != null) {fast = fast.next.next;slow = slow.next;}// 此时 slow 为中间节点// 翻转 slow 以及 slow 后面的节点ListNode behind = new ListNode();ListNode cur = slow;while (cur != null) {ListNode next = cur.next;cur.next = behind.next;behind.next = cur;cur = next;}// 合并两个链表ListNode cur1 = head, cur2 = behind.next;while (cur2.next != null && cur1.next != null) {ListNode next1 = cur1.next, next2 = cur2.next;cur2.next = next1;cur1.next = cur2;cur1 = next1;cur2 = next2;}}
}

看了题解之后,发现可以把整个链表拆成两份.
而且,发现从中间节点的后一个开始翻转链表也可以过,这样就可以在中间节点这个位置把链表分成两份:

  • 一份是 中间节点之前(包含中间节点)
  • 另一份是 中间节点之后

题解代码:

    class Solution {public void reorderList(ListNode head) {// 1.寻找中间节点ListNode slow = head, fast = slow;while (fast != null && fast.next != null) {slow = slow.next;fast = fast.next.next;}ListNode head2 = new ListNode(-1);// 2.逆序 head2 链表ListNode cur = slow.next;// 拆分成两个链表slow.next = null;while (cur != null) {ListNode next = cur.next;cur.next = head2.next;head2.next = cur;cur = next;}// 3. 合并两个链表ListNode head3 = new ListNode(-1);ListNode cur2 = head;ListNode cur3 = head2.next;ListNode prev = head3;while (cur2 != null) {prev.next = cur2;prev = cur2;cur2 = cur2.next;if (cur3 != null) {prev.next = cur3;prev = cur3;cur3 = cur3.next;}}}}

合并 K 个升序链表

在这里插入图片描述
解法一: 不断合并两个链表

/*** Definition for singly-linked list.* public class ListNode {* int val;* ListNode next;* ListNode() {}* ListNode(int val) { this.val = val; }* ListNode(int val, ListNode next) { this.val = val; this.next = next; }* }*/
class Solution {private ListNode mergeLists(ListNode l1, ListNode l2) {if (l1 == null)return l2;if (l2 == null)return l1;ListNode head = new ListNode(-1);ListNode cur1 = l1, cur2 = l2, tail = head;while (cur1 != null && cur2 != null) {if (cur1.val <= cur2.val) {tail.next = cur1;tail = cur1;cur1 = cur1.next;} else {tail.next = cur2;tail = cur2;cur2 = cur2.next;}}while (cur1 != null) {tail.next = cur1;tail = cur1;cur1 = cur1.next;}while (cur2 != null) {tail.next = cur2;tail = cur2;cur2 = cur2.next;}return head.next;}public ListNode mergeKLists(ListNode[] lists) {int n = lists.length;if (n <= 0)return null;ListNode head = lists[0];for (int i = 1; i < n; i++) {head = mergeLists(head, lists[i]);}return head;}
}

方法二: 使用优先级队列优化.

  • 给每个链表都指定一个指针(用来遍历链表),把每一个指针指向的节点放到优先级队列里.不断取出值最小的那个节点,尾插到结果链表中.

忘了怎么在java中自定义排序优先级队列了。

/*** Definition for singly-linked list.* public class ListNode {* int val;* ListNode next;* ListNode() {}* ListNode(int val) { this.val = val; }* ListNode(int val, ListNode next) { this.val = val; this.next = next; }* }*/
class Solution {public ListNode mergeKLists(ListNode[] lists) {int n = lists.length;if (n == 0)return null;// 指针数组ListNode[] arr = new ListNode[n];// 默认是小根堆PriorityQueue<ListNode> heap = new PriorityQueue<>(new Comparator<ListNode>() {@Overridepublic int compare(ListNode o1, ListNode o2) {return o1.val - o2.val;}});// 结果ListNode ret = new ListNode(-1);ListNode tail = ret;// 把指针对应起来for (int i = 0; i < n; i++) {arr[i] = lists[i];}for (int i = 0; i < n; i++) {if (arr[i] != null) {heap.add(arr[i]);}}while (!heap.isEmpty()) {// 最小的出堆ListNode min = heap.poll();// 拼到结果后面tail.next = min;tail = tail.next;if (min.next != null) {// 不为空,入堆heap.add(min.next);}}return ret.next;}
}

看了题解代码后,发现自己写的代码浪费了很多空间,我为什么要 new 一个指针数组???

题解代码:

        /*** Definition for singly-linked list.* public class ListNode {* int val;* ListNode next;* ListNode() {}* ListNode(int val) { this.val = val; }* ListNode(int val, ListNode next) { this.val = val; this.next = next; }* }*/class Solution {public ListNode mergeKLists(ListNode[] lists) {int n = lists.length;if (n == 0)return null;// 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(-1);ListNode tail = ret;while (!heap.isEmpty()) {// 最小的出堆ListNode min = heap.poll();// 拼到结果后面tail.next = min;tail = tail.next;if (min.next != null) {// 不为空,入堆heap.add(min.next);}}return ret.next;}}

方法三:使用 分治 - 递归 解决

好难想到。

代码:

        /*** Definition for singly-linked list.* public class ListNode {* int val;* ListNode next;* ListNode() {}* ListNode(int val) { this.val = val; }* ListNode(int val, ListNode next) { this.val = val; this.next = next; }* }*/class Solution {// 合并两个有序链表public ListNode mergeLists(ListNode l1, ListNode l2) {if (l1 == null)return l2;if (l2 == null)return l1;ListNode head = new ListNode(-1);ListNode tail = head;while (l1 != null && l2 != null) {if (l1.val <= l2.val) {tail.next = l1;l1 = l1.next;} else {tail.next = l2;l2 = l2.next;}tail = tail.next;}while (l1 != null) {tail.next = l1;l1 = l1.next;tail = tail.next;}while (l2 != null) {tail.next = l2;l2 = l2.next;tail = tail.next;}return head.next;}// 递归public ListNode merge(ListNode[] lists, int start, int end) {if (start >= end)return lists[start];int mid = start + (end - start) / 2;ListNode l1 = merge(lists, start, mid);ListNode l2 = merge(lists, mid + 1, end);return mergeLists(l1, l2);}public ListNode mergeKLists(ListNode[] lists) {int n = lists.length;if (n == 0)return null;return merge(lists, 0, n - 1);}}

自己的代码中的合并两个有序链表的代码写的不是很好,最后的 while 可以换成 if 来写的,这是链表,不是数组,不用循环那么多次。。

题解代码:

        /*** Definition for singly-linked list.* public class ListNode {* int val;* ListNode next;* ListNode() {}* ListNode(int val) { this.val = val; }* ListNode(int val, ListNode next) { this.val = val; this.next = next; }* }*/class Solution {// 合并两个有序链表public ListNode mergeLists(ListNode l1, ListNode l2) {if (l1 == null)return l2;if (l2 == null)return l1;ListNode head = new ListNode(-1);ListNode tail = head;while (l1 != null && l2 != null) {if (l1.val <= l2.val) {tail.next = l1;l1 = l1.next;} else {tail.next = l2;l2 = l2.next;}tail = tail.next;}if (l1 != null)tail.next = l1;if (l2 != null)tail.next = l2;return head.next;}// 递归public ListNode merge(ListNode[] lists, int start, int end) {if (start >= end)return lists[start];// 1. 平分数组int mid = start + (end - start) / 2;// 2. 递归处理左右两个部分ListNode l1 = merge(lists, start, mid);ListNode l2 = merge(lists, mid + 1, end);// 3. 合并两个有序链表return mergeLists(l1, l2);}public ListNode mergeKLists(ListNode[] lists) {int n = lists.length;if (n == 0)return null;return merge(lists, 0, n - 1);}}

K 个一组翻转链表

在这里插入图片描述

自己写的代码:

/*** Definition for singly-linked list.* public class ListNode {* int val;* ListNode next;* ListNode() {}* ListNode(int val) { this.val = val; }* ListNode(int val, ListNode next) { this.val = val; this.next = next; }* }*/
class Solution {public ListNode reverse(ListNode head, int k) {ListNode phead = new ListNode(-1);ListNode cur = head, next = cur.next;while (k-- > 0) {cur.next = phead.next;phead.next = cur;cur = next;if (next != null)next = next.next;elsebreak;}return phead.next;}public ListNode reverseKGroup(ListNode head, int k) {ListNode phead = new ListNode(-1);phead.next = head;ListNode slow = phead, fast = head;while (fast != null) {int tmp = k;while (tmp > 0) {if (fast == null) {break;}fast = fast.next;tmp--;}if (tmp > 0)break;slow.next = reverse(slow.next, k);tmp = k;// 写成这样你要清楚:// 等出循环的时候 tmp = -1// 因为在最后一次的判断时 tmp 也要 --while (tmp-- > 0) {slow = slow.next;}slow.next = fast;}return phead.next;}
}

题解代码:

/*** Definition for singly-linked list.* public class ListNode {* int val;* ListNode next;* ListNode() {}* ListNode(int val) { this.val = val; }* ListNode(int val, ListNode next) { this.val = val; this.next = next; }* }*/
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(-1);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 个的情况prev.next = cur;return newHead.next;}
}

总结

链表常用技巧 :

  1. 画图是个好东西(感觉好像已经说过好几遍了).
  2. 可以引入一个头结点
    • 便于处理边界情况
    • 方便我们对链表操作
  3. 在插入新节点时,可以先把新节点的指针指向都调整好.然后再去调整前一个节点和后一个节点.
    或者直接新建一个指针,指向后一个节点,这样更容易操作~
  4. 有时候会用到快慢双指针

本文到这里就结束啦~

在这里插入图片描述

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

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

相关文章

深入Pillow:处理图像下载中的意外挑战

在当今数字化时代&#xff0c;获取和处理图像数据已经成为了许多应用程序的核心功能。从社交媒体到电子商务&#xff0c;图像的获取和处理对于用户体验至关重要。下载图片不仅能够丰富我们的内容&#xff0c;还能够通过分析图像数据为我们的应用提供更多价值。然而&#xff0c;…

零基础Java第十三期:继承与多态(一)

目录 一、继承 1.1. 继承的目的 1.2. 继承的概念 1.3. 继承的语法 1.4. 父类的访问 1.5. 继承中的重载与重写 1.6. 子类的构造方法 1.7. 再谈初始化 一、继承 1.1. 继承的目的 我们来定义一个Dog和Cat的类&#xff1a; public class Dog {public int age;public Strin…

【ONLYOFFICE文档】8.2版本测评

文章目录 引言ONLYOFFICE 产品简介PDF编辑器新功能1.协作编辑 PDF&#xff0c;让团队合作更高效2.为 PDF 表单添加签名3.改进的简洁界面4.性能优化&#xff1a;更快、更高效的体验 文档编辑器中的新功能域代码功能&#xff1a;自动更新文档中的动态数据协作功能&#xff1a;轻松…

【JAVA】java 企业微信信息推送

前言 JAVA中 将信息 推送到企业微信 // 企微消息推送messageprivate String getMessage(String name, String problemType, String pushResults, Long orderId,java.util.Date submitTime, java.util.Date payTime) {String message "对接方&#xff1a;<font color\…

【RK3588 Linux 5.x 内核编程】-GPIO设备驱动与点亮LED

GPIO设备驱动与点亮LED 文章目录 GPIO设备驱动与点亮LED1、Linux中的GPIO介绍2、GPIO库和工具3、Linux内核GPIO操作步骤3.1 验证GPIO3.2 请求GPIO3.3 导出GPIO到sysfs(可选)3.4 设置GPIO为输入/输出3.5 更改GPIO的电平(值)3.6 读取GPIO的值(电平)3.7 释放GPIO4、GPIO驱动…

金华迪加 现场大屏互动系统 mobile.do.php 任意文件上传漏洞复现

0x01 产品简介 金华迪加现场大屏互动系统是一种集成了先进技术和创意设计的互动展示解决方案,旨在通过大屏幕和多种交互方式,为观众提供沉浸式的互动体验。该系统广泛应用于各类活动、展览、会议等场合,能够显著提升现场氛围和参与者的体验感。 0x02 漏洞概述 金华迪加 现…

[VUE]框架网页开发1 本地开发环境安装

前言 其实你不要看我的文章比较长&#xff0c;但是他就是很长&#xff01;步骤其实很简单&#xff0c;主要是为新手加了很多解释&#xff01; 步骤一&#xff1a;下载并安装 Node.js 访问 Node.js 官网&#xff1a; Node.js — Download Node.js 下载 Windows 64 位版本&…

[signal] void QComboBox::currentTextChanged(const QString text)

[signal] void QComboBox::currentTextChanged(const QString &text) This signal is sent whenever currentText changes. The new value is passed as text. This function was introduced in Qt 5.0. Note: Notifier signal for property currentText. 属性currentText的…

Unity中实现伤害飘字或者提示飘字效果(DoTween实现版本)

&#xff01;&#xff01;&#xff01;在实现以下效果之前&#xff0c;一定要往项目中导入DoTween插件。 一、搭建测试场景 1、在场景中新建一个带有Text组件的游戏物体A&#xff0c;并把这个游戏物体A中Text组件的Color属性中alpha值为0&#xff0c;让文字在场景中隐藏。 …

掌握PyQt5图形界面化工具及绑定爬虫程序

PyQT5——图形化界面 文章目录 PyQT5——图形化界面集成化图形界面工具为什么使用 \$ProjectFileDir$?示例场景其他 Varaiablespyuic参数解释整体含义示例使用PyQt5和pyuic 创建pyqt5的程序创建一个窗口app.exec\_()和sys.exit(app.exec_())的区别1. app.exec_()2. sys.exit(a…

从零开始在本地服务器上安装OnlyOffice并进行跨地域协同编辑文件

文章目录 前言1. 安装Docker2. 本地安装部署ONLYOFFICE3. 安装cpolar内网穿透4. 固定OnlyOffice公网地址 前言 本篇文章讲解如何使用Docker在本地Linux服务器上安装ONLYOFFICE&#xff0c;并结合cpolar内网穿透实现公网访问本地部署的文档编辑器与远程协作。 Community Editi…

20241102在荣品PRO-RK3566开发板的预置Android13下适配宸芯的数传模块CX6603N

20241102在荣品PRO-RK3566开发板的预置Android13下适配宸芯的数传模块CX6603N 2024/11/2 18:04 在WIN10使用程序&#xff1a;ViewLink-4.0.7_0708-windows-x64.exe 在荣品PRO-RK3566开发板的预置Android13下使用&#xff1a;ViewLink-2023_12_21-release-0.2.6.apk adb install…

智能AI合同审查系统如何优化合同风险管理的案例解读

在合同管理和合规性要求日趋严格的法律行业&#xff0c;智能合同审查系统能够大幅提升合同数据管理的效率和准确性。法律行业中&#xff0c;合同涉及金额、产品参数和条款细节较多&#xff0c;同时对合规性有极高的要求。特别是在高度受监管的行业&#xff08;如金融、医疗、制…

C++《list的模拟实现》

在上一篇C《list》专题当中我们了解了STL当中list类当中的各个成员函数该如何使用&#xff0c;接下来在本篇当中我们将试着模拟实现list&#xff0c;在本篇当中我们将通过模拟实现list过程中深入理解list迭代器和之前学习的vector和string迭代器的不同&#xff0c;接下来就开始…

Vue学习之路17----事件

可以自定义事件让子组件向父组件传值 1.使用emit 2.使用props 3.使用mitt 其实mitt和第一种方法类似&#xff0c;都用emitt事件&#xff0c;但是mitt不局限于父子之间通信&#xff0c;他可以在任意2个组件之间通信&#xff0c; 虽然需要安装&#xff0c;但mitt很小&#xff…

网络安全认证的证书有哪些?

在网络安全领域&#xff0c;专业认证不仅是个人技术能力的象征&#xff0c;也是职业发展的重要推动力。随着网络安全威胁的日益严峻&#xff0c;对网络安全专业人才的需求也在不断增长。本文将介绍一些网络安全认证的证书&#xff0c;帮助有志于从事网络安全行业的人士了解并选…

D59【python 接口自动化学习】- python基础之异常

day59 捕获异常常见问题 学习日期&#xff1a;20241105 学习目标&#xff1a;异常 -- 75 避坑指南&#xff1a;编写捕获异常程序时经常出现的问题 学习笔记&#xff1a; 捕获位置设置不当 设置范围不当 捕获处理设置不当 嵌套try-except语法错误 总结 位置&#xff0c;范围…

yelp数据集上试验SVD,SVDPP,PMF,NMF 推荐算法

SVD、SVD、PMF 和 NMF 是几种常见的推荐算法&#xff0c;它们主要用于协同过滤和矩阵分解方法来生成个性化推荐。下面是对每种算法的简要介绍&#xff1a; 1. SVD&#xff08;Singular Value Decomposition&#xff09; 用途&#xff1a;SVD 是一种矩阵分解技术&#xff0c;通…

C++ | Leetcode C++题解之第540题有序数组中的单一元素

题目&#xff1a; 题解&#xff1a; class Solution { public:int singleNonDuplicate(vector<int>& nums) {int low 0, high nums.size() - 1;while (low < high) {int mid (high - low) / 2 low;mid - mid & 1;if (nums[mid] nums[mid 1]) {low mid…

Python练习7

Python日常练习 题目&#xff1a; 编写程序&#xff0c;输出由1、2、3、4这四个数字组成的每位数都不相同的所有三位数 要求&#xff1a; 每个数字用换行隔开 --------------------------------------------------------- 注意&#xff1a; 部分源程序给出如下。请勿改动…