算法之链表

news/2024/12/16 11:30:45/文章来源:https://www.cnblogs.com/exo123/p/18609667

链表

移除链表元素

对于链表来说,删除头节点和中间节点具体操作不一样是因为想要删除一个中间节点,必须要知道该节点的前一个节点,而头节点没有前一个节点。

  使用虚拟头节点,统一节点的删除操作,用一个虚拟头节点的next指向head,这个链表中的每个元素都会有前一个节点,从而对所有节点都可以统一使用前一个节点进行删除。

最后是返回原虚拟头节点的下一个节点,才是新的修改过的链表,而不能直接返回原先的head。

找到原因:如果删除的是头节点,head指向的节点并不会被删除,更新的是p指向的链表,所有综合起来直接返回虚拟头节点的下一个节点

public ListNode removeElements1(ListNode head, int val) {ListNode p=new ListNode();ListNode q=new ListNode();//是虚拟头节点p.next=head;//临时指针 遍历链表(包括虚拟头节点)q=p;while (p.next!=null){if (p.next.val==val){p.next=p.next.next;}else {p=p.next;}}return q.next; //不能直接返回head,调试后发现p指向的链表会改变,但head所在的链表并没有随之改//变,只有再添加一个node节点让它等于p
}

 

设计链表

对于链表的操作需要在节点的基础上增加一个虚拟头节点dummy node,它的next指向链表的头节点,再创建一个当前节点curr=dummy node,使用当前节点对链表进行操作,增删之后再使得head=dunmmy node.next。

为什么增删后要执行head=dunmmy node.next?因为对于链表的增删操作很有可能会删除头节点或者将头节点后移,此时光靠头节点是没办法得到最新的链表的,但虚拟头节点的位置是不会变的,所以要根据虚拟头节点找到head。

查看代码
 public class MyLinkedList {int length;listNode head;public MyLinkedList() {}public MyLinkedList(int length, listNode head) {this.length = length;this.head = head;}public int get(int index){listNode p=head;if (index<length){for (int i = 0; i < index; i++) {p=p.next;}return p.val;}else {return -1;}}public void addAtHead(int val){listNode newNode=new listNode();newNode.val=val;newNode.next=head;head=newNode;//这里直接用了headlength=length+1;}public void addAtTail(int val){listNode newNode=new listNode();newNode.val=val;listNode p=new listNode();p.next=head;listNode q=new listNode();q=p;while (p.next!=null){//找到插入节点的前一个节点p=p.next;}p.next=newNode;head=q.next;//如果此时链表为空,加在末尾的也是头节点,但此时head经过上面的操作并没有发生改变,因此要更新length+=1;}public void addAtIndex(int index,int val){listNode newNode=new listNode(val);listNode p=new listNode();p.next=head;listNode q=p;if (index<=length){for (int i = 0; i < index; i++) {p=p.next;//得到前一个}newNode.next=p.next;p.next=newNode;head=q.next;//必须要加上这句,如果此时插入的是头节点,head节点会放到新插入节点的后面,根据head并不能返回最新的链表 但如果插入的是中间节点,则直接用head即可length=length+1;}}public void deleteAtIndex(int index){listNode p=new listNode();p.next=head;listNode q=new listNode();q=p;if (index<length){for (int i = 0; i < index; i++) {p=p.next;}p.next=p.next.next;head=p.next;//同理 如果删除的是头节点的话 必须要同步更新length-=1;}}}

 

翻转链表

使用双指针思想,curr指向头节点,pre为null,再用一个临时节点temp保存curr.next.

查看代码
  public ListNode reverseList(ListNode head) {ListNode pre=null;ListNode curr=head;ListNode temp=new ListNode();while (curr!=null){temp=curr.next;curr.next=pre;pre=curr;curr=temp;}return pre;}

 

两两交换链表中的节点

问题:没有将虚拟头节点的指针重新指向排序后的头节点,造成排序后第一个节点消失

查看代码
  public ListNode swapPairs(ListNode head) {ListNode dummyNode=new ListNode();dummyNode.next=head;ListNode pre=dummyNode;ListNode curr1=pre.next;ListNode curr2=null;if (curr1!=null &&curr1.next!=null){curr2=curr1.next;}ListNode temp;while (curr1!=null && curr2!=null){temp=curr2.next;pre.next=curr2;curr2.next=curr1;curr1.next=temp;pre=curr1;curr1=temp;if (temp!=null){curr2=temp.next;}}return dummyNode.next;}

删除链表的倒数第N个节点

思路:使用前后指针,中间间隔节点数为倒数节点个数-1。

查看代码
 public ListNode removeNthFromEnd(ListNode head, int n) {ListNode dummyNode=new ListNode();dummyNode.next=head;ListNode preN=dummyNode;ListNode curr=dummyNode;while (n-->0){curr=curr.next;}while(curr.next!=null){preN=preN.next;curr=curr.next;}preN.next= preN.next.next;return dummyNode.next;}

其中在对链表节点进行增加时,不能直接新建节点来接收更新的list.head值,否则list中的head是没有更新的

MyLinkedList list=new MyLinkedList();int[] arr=new int[]{1,2,3,4,5};for (int i = 0; i < arr.length; i++) {list.head = list.addLinkedlist(arr[i]);//不能新建一个ListNode为head 而是把这个链表的head值进行更新}
//        list.printLinkedlist(list.head);list.head = removeNthFromEnd(list.head, 1);list.printLinkedlist(list.head);

链表相交

该题的初始化无法使用简单的增加链表节点,如果让输入的两个数组独立进行链表初始化,即使值相同但并不能指向同一节点。

思路:将两个链表进行等长操作,具体为求出两个链表的长度,然后将长链表的当前指向节点往后移动直到和短链表的头节点位置相同,然后开始顺序比较每个节点是否相同(注意:不是节点的值,而是节点!!

查看代码
         int lengthA=0;int lengthB=0;ListNode currA=headA;ListNode currB=headB;while (currA!=null || currB!=null){if (currA!=null){lengthA+=1;currA=currA.next;}if (currB!=null){lengthB+=1;currB=currB.next;}}currA=headA;currB=headB;int gap=Math.abs(lengthA-lengthB);while (gap-->0){if (lengthA>lengthB){currA=currA.next;}else {currB=currB.next;}}while (currA!=null && currB!=null){if (currA==currB){return currA;}currA=currA.next;currB=currB.next;}return null;

环形链表II

要掌握它们之间的数学关系,才能解此题,两个关键点:第一是通过快慢指针,当相遇时一定在环内,得到相遇节点;第二是根据数学公式(x+y)*2=x+y+n(y+z),得到x=(n-1)(y+z)+z,即当指针从头节点和相遇节点同时出发时,一定会再次相遇,再次相遇的节点为环形入口节点。

查看代码
 public ListNode detectCycle(ListNode head) {ListNode fast=head;ListNode slow=head;while(fast!=null &&  fast.next!=null){slow=slow.next;fast=fast.next.next;if(slow==fast){ListNode index1=fast;ListNode index2=head;while(index1!=index2){index1=index1.next;index2=index2.next;}return index1;}}return null;

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

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

相关文章

算法之数组

数组 二分查找 给定一个排序数组和一个目标值,在数组中找到目标值,并返回其索引。如果目标值不存在于数组中,返回它将会被按顺序插入的位置。 题解:如果等于nums[middle],返回middle;否则返回left或者low。移除元素 在排序数组中查找target的开始位置和结束位置。 二分法不…

年会筹备大揭秘:看板软件如何助力团队协作?

看板软件以其直观、灵活和高效的特点,成为企业年会准备的得力助手。通过看板软件,企业可以更加高效地组织和管理年会筹备工作,确保活动的顺利进行,并为企业文化的传播和员工凝聚力的提升做出贡献。看板软件以其直观、灵活和高效的特点,成为企业年会准备的得力助手。通过看…

【每日一题】20241216

我做出了选择。也许不是好的选择,但选择了就要承担后果。【每日一题】已知函数 \(f(x)=\sin|x|+2|\sin x|\),则 \(f(x)\) 在 \((-2\pi,\pi)\) 的零点个数为________. 已知函数 \(f(x)(x\in\mathbf{R})\) 满足 \(f(-x)=2-f(x)\).设方程 \(f(x)-\frac{x+1}{x}=0\) 的 \(m\) 个…

ARMS 用户体验监控正式发布原生鸿蒙应用 SDK

原生鸿蒙系统是我国首个实现全栈自研的操作系统,全面突破操作系统核心技术,真正实现了国产操作系统的自主可控。在这样的背景下,RUM 推出的用于监控原生鸿蒙的 SDK 为鸿蒙应用的开发者提供了更进一步的便利,对衡量用户体验关键的指标进行全面的分析和追踪。作者:杨兰馨(楠…

零基础学习人工智能—Python—Pytorch学习(十二)

前言 本文介绍使用神经网络进行实战。 使用的代码是《零基础学习人工智能—Python—Pytorch学习(九)》里的代码。 代码实现 mudule定义 首先我们自定义一个module,创建一个torch_test17_Model.py文件(这个module要单独用个py文件定义),如下: import torch.nn as nn import…

700PB数据的数仓依然“快稳省”!ByteHouse这本白皮书揭秘关键(内附下载链接)

12月10日,《火山引擎ByteHouse云数仓产品白皮书》在线上发布。在数字经济蓬勃发展的今天,企业面临着数据量爆炸性增长、数据分析需求日益复杂的双重挑战。传统的数据仓库解决方案已经难以满足企业对数据处理速度和灵活性的高要求。为了应对这些挑战,火山引擎于2021年正式推出…

子查询关联条件字段没有指定表的别名导致的查询结果不正确的问题

子查询关联查询问题,子查询关联条件字段没有指定表的别名导致的查询结果不正确的问题首先介绍一下表结构和背景;有两个数据库表,供应商XX任务主表和供应商等级变更记录表; 等级表里面有多个任务,两张表是通过同名称的字段,supplier_id关联; ①SQL是XX任务表关联供应商等…

Xinference环境搭建推理测试

引子 写了很多篇开源大模型的环境部署与推理搭建,截止到目前,开源大模型已经发展较为完善。个人觉得,产品和项目维度来看更多的是如果去落地实现,也就是大模型的最后一公里的应用开发。最近看到Xinference一个开源很火的推理框架。OK,那就让我们开始吧。 一、框架介绍 Xin…

前端工程化_CSS 工具链_学习笔记

本文主要介绍了 CSS 工具链,可以看出工具链的出现都是为了解决语言的问题,文中就介绍了预处理器和后处理器,预处理器主要介绍了 sass,并举了星空这个例子,sass 是通过与预编译器编译成 css 后给 html 使用;后处理器则介绍了 postcss,其中 postcss 和 babel 类似,都有很…

车载以太网TSN设计及测试解决方案

智能汽车电子电气架构全面向中央+区域式发展,车载通信新技术是新架构技术栈的重要组成部分。车载以太网时间敏感网络TSN技术凭借其低延时、高可靠的特点获得多家OEM的认可。依赖多年技术研发及数十个项目的实践积累,经纬恒润可为客户提供全面、专业且本土化的TSN设计与测试解…

看板软件:跨境电商圣诞营销加速器

看板软件在跨境电商中发挥着多重作用,特别是在圣诞节这一关键销售时期。通过清晰有序的任务管理、灵活适配的自定义功能、高效的信息整合与数据分析、以及精准有效的营销策略应用,看板软件显著提升了跨境电商团队的协作效率和销售能力。圣诞节作为全球最重要的购物节日之一,…

LameUI:轻量级嵌入式图形用户界面的绝佳选择

在信息技术迅猛发展的今天,嵌入式系统逐渐成为各种智能设备的核心。这些系统往往面临资源有限的挑战,因此在开发用户界面时,使用轻量级、易于实现的库显得尤为重要。在这种背景下,LameUI 应运而生。作为一个轻量级且平台无关的图形用户界面库,LameUI 旨在为开发者提供简便…