java算法day3

  • 移除链表元素
  • 设计链表
  • 翻转链表
  • 两两交换链表中的结点

移除链表元素

ps:有时候感觉到底要不要写特判,你想到了就写!因为一般特判有一劳永逸的作用。

解法有两种,一种是不用虚拟头结点,另一种就是用虚拟头结点。
这里我习惯用虚拟头结点。不用虚拟头结点就需要自己写头结点的特判。

请添加图片描述
虚拟头结点的好处:方便对每个结点进行统一处理,不用写特判。

解法:双指针
链表的删除操作并不是要找目标元素才能完成删除,而是找目标元素的前一个元素才能完成删除。所以需要一个pre用于指向目标元素的前一个元素,cur用来指向目标元素。

算法流程
cur指针进行判断,如果不是cur指向的不是目标元素,双方一起往后走。pre = cur。cur = cur.next。
如果cur指的是目标元素,那么就要完成上面图里面的操作。

pre的next应该指向cur的后面那个元素,所以是pre.next = cur.next。
此时你的pre还在原地,然后cur指的那个元素被删了,然后就后移。

对于写代码:
可以发现不管是不是目标元素,cur始终是要后移的。而pre如果是cur指目标元素后才后移,如果不是目标元素,就一起后移。

/*** 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 removeElements(ListNode head, int val) {if (head == null){return head;  //空链表判断}//链表不空,进入下面的移除逻辑ListNode dummy = new ListNode(-1,head);  //初始化虚拟头结点ListNode pre = dummy;        //由于要进行删除操作,pre应该指向虚拟头结点。ListNode cur = head;		//cur用于遍历,用于寻找目标结点。while(cur!=null){          //遍历结点不为nullif(cur.val==val){        //如果等于目标结点pre.next = cur.next;  //前一个结点的后驱指向遍历结点的后驱,因为此时这个cur指向的元素是要删除的}else{pre = cur;  //这个就是不等于目标结点,就两者同时后移}cur = cur.next;  //不管如何,cur始终在进行遍历,所以要一直后移。}return dummy.next;  //返回虚拟头结点的后一个结点,就是答案。}
}

设计链表

都是链表的基础操作,需要注意的地方就是题目的要求。

这个题是一个非常好的模板。一定要擅长写模板。

本题为了操作方便,所以用了虚拟头结点作为默认初始化

class ListNode{ //结点类。这个数据结构一定要会写int val;ListNode next;ListNode(){}ListNode(int val,ListNode next){this.val = val;this.next = next;}ListNode(int val){this.val = val;}
}class MyLinkedList { //定义i链表//链表两个属性:1.长度和最开始的结点//但是注意这里链表的第一个结点是虚拟头结点//这么设计是为了方便统一操作。int size;ListNode head; //注意这是虚拟头结点//初始化链表,长度为0,然后创建了一个虚拟头结点。//所以一定要注意后续的操作的两个细节//此时链表第一个结点是虚拟头结点,但是我并不把它计入链表长度//然后链表元素下标是从0开始的。后续对index循环那里很重要,小心坑。public MyLinkedList() {size = 0;head = new ListNode(0);}//public int get(int index) {if(index<0 || index>=size){ //因为下标从0开始,所以index=size也会判错return -1;}//创建一个遍历指针,注意这里是指的虚拟头结点。所以后面边界才是<=indexListNode currentNode = head;//开始遍历查找for(int i = 0;i<=index;i++){  //就是因为从虚拟头结点开始,而且结点又是从下标0开始。所以才是取等。相当于多+1currentNode = currentNode.next;  }//最后currentNode会停在index的位置。return currentNode.val;}public void addAtHead(int val) {addAtIndex(0,val); //这就是下面一般情况的应用,由于我是用的带虚拟头结点,所以可以当一般情况来处理。}public void addAtTail(int val) {addAtIndex(size,val);//这就是下面一般情况的应用,由于我是用的带虚拟头结点,所以可以当一般情况来处理。}public void addAtIndex(int index, int val) {//先进行特判 当下标大于链表长度,则不执行插入if(index > size){return;}if(index<0){ //当下标长度为负值,插入到第一个元素,所以这里进行下标的重新修改index = 0;}size++; //要插入,那么链表长度+1ListNode pre = head; //由于要插入到目标之前,所以pre是初始化为虚拟头结点。for(int i = 0;i<index;i++){//由于是要插入到index元素之前,而pre一开始是在虚拟头结点。所以这样会导致pre最终停在index元素之前的那个元素。pre = pre.next;}ListNode insertNode = new ListNode(val);  //定义新插入的结点,这里用一参构造,next默认初始化为null了insertNode.next = pre.next;              //插入操作:新结点的next指向pre的后面那个元素pre.next = insertNode;                   //pre再指向新插入的结点。}public void deleteAtIndex(int index) {//先对index是否有效进行检查if(index < 0  || index>=size){ //下标小于0或者是下标大于或等于链表长度,由于是从0开始,所以等于size也是无效索引。return;}    size--;//删除元素就可以先长度--,因为过了特判就进入了删除逻辑,一定有元素删除ListNode pre = head;//删除就必须要找目标元素的前一个元素,所以从虚拟头结点开始最方便for(int i = 0;i<index;i++){//由于下标从0开始,而pre一开始在虚拟头结点,所以pre最终停在index的前一个位置pre = pre.next;            //不断后移找目标元素的前一个元素}pre.next = pre.next.next;  //进行删除操作}
}/*** Your MyLinkedList object will be instantiated and called as such:* MyLinkedList obj = new MyLinkedList();* int param_1 = obj.get(index);* obj.addAtHead(val);* obj.addAtTail(val);* obj.addAtIndex(index,val);* obj.deleteAtIndex(index);*/

一定要注意题目要求:带虚拟头结点,而且虚拟头结点不计入链表长度。并且下标从0开始。

翻转链表

注意:没有用到虚拟头结点

这个题怎么想:
首先拿到一个链表:
1 -> 2 -> 3 -> null
翻转链表那就是变成3 -> 2 -> 1 -> null
那很容易就能想到,把指针方向翻转就完成了修改。那就往这个方向去做。

如何完成修改,这里采用双指针,加一个tmp指针用于后移的方法。
请添加图片描述
pre一开始指向null,这里可以理解为在翻转过程中,那么第一个结点的next那必然是null。

cur用于遍历构造。

此时想到cur.next = pre ,那不就完成了next后驱的翻转,但是还有个问题,如果直接cur.next = pre,那就找不到后面的结点,无法继续遍历修改链表了。所以这里再加一个tmp用于存往后遍历的位置,这个tmp的值显然就是cur的后驱:cur.next。

所以现在来看完整的过程:
请添加图片描述
先用tmp记录cur的后驱。方便之后后移。
然后现在就可以放心的改指针了。
cur.next = pre。
请添加图片描述
然后pre也要后移,因为之后还有进行cur.next = pre来进行指针修改。你不后移之后不就改不了了。

pre = cur;
请添加图片描述

然后cur进行后移到tmp。
请添加图片描述
从这个过程往后走,cur最终会走到null上,pre最终停留在最后一个结点。所以循环终止条件就是cur!=null,最后返回pre。请添加图片描述

/*** 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 reverseList(ListNode head) {ListNode pre = null; //由于要倒过来,所以pre指在null用于cur改后驱指向。ListNode cur = head; //cur指向head用于遍历while(cur!=null){ListNode tmp = cur.next; //用tmp记录后继,方便改指针之后的后移cur.next = pre; //翻转指针pre = cur; //翻转成功后,前向指针进行后移cur = tmp; //遍历指针后移}return pre;}
}

两两交换链表中的结点

方法:迭代
思路出发:从模拟的角度来
本题是要加虚拟头结点的。因为这更方便处理。上一题就不用加,因为太简单了。对极端情况不敏感还是用虚拟头结点比较好。
请添加图片描述
现在想完成两两交换,那就直接按图来即可。
这里目的是node1,node2完成结点交换。

显然temp.next指向node2,这样node2就到node1的位置来了。请添加图片描述
然后node1现在要作为第二个结点,那就node1指向node2的next结点。请添加图片描述
现在node2的next再指向node1即可。请添加图片描述
现在得到请添加图片描述
前两个就已经改完了,那么现在就要到下一轮,显然temp要变到node1的位置,然后开启下一轮的逻辑。请添加图片描述

最后返回的结果是dummyhead.next

所以现在还剩下两个问题:
1、node1和node2如何定义?
很简单,node1就是temp.next即node1 = temp.next
node2就是temp.next.next即node2 = temp.next.next

2、循环什么时候停止。
思考的突破口在于后移操作,因为在后移的过程中非常害怕空指针。所以后移的空指针是处理就是循环终止的关键。

后移与否就要考虑后面的指针空不空,而且一开始我的temp在虚拟头结点上。
所以循环条件就是:
while(temp.next!=null && temp.next.next!=null)
不能往后移了,代表循环该停了。

如果对极端情况有疑问,把上面那个图截取一部分思考即可。效果是一样的。这就是虚拟头结点的统一处理效果。

/*** 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 swapPairs(ListNode head) {ListNode dummyhead = new ListNode(0);//创建一个虚拟头结点dummyhead.next = head;  //把虚拟头结点加到链表的头部去ListNode temp = dummyhead;  //创建迭代的指针temp。while(temp.next!=null && temp.next.next!=null){ListNode node1 = temp.next; //定义node1ListNode node2 = temp.next.next; //定义node2//开始进行交换操作,下面三行代码看图来做很清晰temp.next = node2;  node1.next = node2.next;node2.next = node1;//注意是指向node1,因为node1被换到了后面去。temp = node1;}return dummyhead.next;}
}

这里我还发现一个习惯,一般迭代操作,都习惯去创建一个遍历指针去迭代。这样更加方便,原本代表链表的指针不要动,可以用来做结果的返回。

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

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

相关文章

React-基础语法学习

1、教程&#xff1a;井字棋游戏 本教程将引导你逐步实现一个简单的井字棋游戏&#xff0c;并且不需要你对 React 有任何了解。在此过程中你会学习到一些编写 React 程序的基本知识&#xff0c;完全理解它们可以让你对 React 有比较深入的理解。 1.1、教程分成以下几个部分&am…

3D感知生成对抗网络的高斯溅射解码器

Gaussian Splatting Decoder for 3D-aware Generative Adversarial Networks 3D感知生成对抗网络的高斯溅射解码器 Florian Barthel1, 2  Arian Beckmann1  Wieland Morgenstern1  Anna Hilsmann1  Peter Eisert1,2 Florian Barthel 1, 2 阿里安贝克曼Wieland晨星Anna Hils…

【Godot4自学手册】第三十九节利用shader(着色器)给游戏添加一层雾气效果

今天&#xff0c;主要是利用shader给游戏给地宫场景添加一层雾气效果&#xff0c;增加一下气氛&#xff0c;先看一下效果&#xff1a; 一、新建ParallaxBackground根节点 新建场景&#xff0c;根节点选择ParallaxBackground&#xff0c;命名为Fog&#xff0c;然后将该场景保…

不要小看在线文档编辑工具,它才是提高工作效率的法宝

在数字化的今天&#xff0c;工作方式正变得越来越灵活&#xff0c;远程办公和团队协作已成日常。这个时候&#xff0c;传统的文档处理方式已经无法满足快速发展的业务需求。在线文档编辑工具&#xff0c;正逐渐成为提高团队工作效率的秘密武器。它能够让团队成员无论身处何地&a…

从预训练损失的角度,理解语言模型的涌现能力

原文&#xff1a;Understanding Emergent Abilities of Language Models from the Loss Perspective 摘要 本文从预训练损失的角度重新审视语言模型的涌现能力&#xff0c;挑战了以往以模型大小或训练计算量为标准的观念。通过实验&#xff0c;作者发现预训练损失是预测下游任…

【剪映专业版】15绿幕抠图:应用技巧、注意事项

视频课程&#xff1a;B站有知公开课【剪映电脑版教程】 1.绿幕抠图 背景为绿色的素材&#xff08;其他颜色也可以扣取&#xff0c;只是绿色背景更普遍、抠图效果更好&#xff09; 选择色度抠图&#xff0c;通过取色器选取背景颜色&#xff0c;调整强度实现抠图 剪映的色度抠…

“我舍不得”用英语怎么说?柯桥日常英语口语培训

“我舍不得”用英语怎么说&#xff1f; “舍不得”的英文表达是&#xff1a;Cant bear to 不忍心&#xff0c;不舍得 例句&#xff1a; Time flies. I cant bear to leave you. 时间过的好快啊&#xff0c;我真舍不得离开你。 I cant bear to see you cry. 我真舍不得你…

《QT实用小工具·三十四》Qt/QML使用WebEngine展示的百度ECharts图表Demo

1、概述 源码放在文章末尾 该项目实现了百度ECharts图表的样式&#xff0c;效果demo如下所示&#xff1a; 项目部分代码如下所示&#xff1a; #include <QGuiApplication> #include <QQmlApplicationEngine> #include <QtWebEngine>int main(int argc, ch…

小成本搏大流量:微信/支付宝小程序搜索排名优化

随着移动互联网的快速发展&#xff0c;小程序已成为企业和个人开发者重要的流量入口和业务承载平台。而小程序搜索排名则是影响小程序曝光量、用户获取及业务转化的关键因素。小柚在本文和大家探讨如何制定有效的优化方案&#xff0c;提升小程序在搜索结果中的排名。 首先跟我…

基于docker的Jenkin的服务平台搭建

项目拓扑图 项目环境: jenkins-2.440 sonarqube-9.9.4 apache-maven-3.9.6 gitlab-ce-12.4.2 java17 docker20 harbor.v2.6.0 centos7.9 项目目的: 模拟企业构建一个流行的持续集成和持续部署环境,可以更轻松地创建和管理构建环境&#xff0c;实现自动化构建和部署应用程序的…

Ubuntu 微调训练ChatGLM3大语言模型

Ubuntu 微调训练ChatGLM3大语言模型 LLaMA Factory 的 LoRA 微调提供了 3.7 倍的加速比&#xff0c;同时在广告文案生成任务上取得了更高的 Rouge 分数。结合 4 比特量化技术&#xff0c;LLaMA Factory 的 QLoRA 微调进一步降低了 GPU 显存消耗。 https://github.com/hiyouga…

累加(C语言)

一、题目&#xff1b; 二、N-S流程图&#xff1b; 三、运行结果&#xff1b; 四、源代码&#xff1b; # define _CRT_SECURE_NO_WARNINGS # include <stdio.h>int main() {//初始化变量值&#xff1b;int i 0;int j 0;int n 5;int result 0;int sum 0;//运算&#…

牛客-小乐乐与欧几里得

目录 题目 描述 输入描述&#xff1a; 输出描述&#xff1a; 示例1 示例2 解题 题目 描述 小乐乐最近在课上学习了如何求两个正整数的最大公约数与最小公倍数&#xff0c;但是他竟然不会求两个正整数的最大公约数与最小公倍数之和&#xff0c;请你帮助他解决这个问题。 …

进程控制第二弹(进程程序替换)

文章目录 代码现象基本原理多进程版本实例基本原理 使用所有的替换方法&#xff0c;并且认识函数的参数含义execlexecvexeclp、execvpexecvpe 总结 代码现象 #include<stdio.h> #include<unistd.h> int main() { printf("testexec begin! ...\…

数据安全全面防护

what 通过采用各种有效技术和管理措施来保护网络系统的正常运行&#xff0c;从而保证数据的可用性&#xff0c;机密性&#xff0c;完整性。 ---网络安全防护体系建设三同步--规划 建设 运行 数据安全的三大基本特征 可用性 数据在需要时可用且可访问&#xff0c;为实现可用…

算法课程笔记——STL键值对map

map当下标无限的数组 重点是对应关系&#xff0c;一般不修改compare 类比set 没有lowerbound&#xff0c;因为遍历是无序的 ; map不能用sort函数排序 但可用vector转化为map使用 std::set<std::pair<TKEY, mutable TVAL> > ≈ std::map<TKEY, TVAL>

【剪映专业版】13快速为视频配好音:清晰、无噪声、对齐

视频课程&#xff1a;B站有知公开课【剪映电脑版教程】 使用场景&#xff1a;视频无声音或者视频有声音但是需要更改声音 时间指示器在哪里&#xff0c;就从哪里开始 红色按钮&#xff1a;开始录音 声音波纹&#xff1a;蓝色最佳&#xff0c;黄色或红色声音太大&#xff0c;…

Unity UGUI透明区域点击无效

是这样的&#xff0c;我有一张图&#xff0c;客户给的是1920*1080&#xff0c;但只有中间部分是按钮&#xff0c;是有效像素。为了让空白区域点击无效。需要设置如下 并且加上下面这句 this.GetComponent<Image>().alphaHitTestMinimumThreshold 0.1f;

python学习笔记B-08:序列结构之列表--列表的遍历操作

列表的遍历方法主要有三种&#xff0c;使用方法和特点如下&#xff1a; lst list("hello") print("第一种遍历方式&#xff0c;使用for循环&#xff0c;循环变量item直接就是lst中的元素") for item in lst:print(item,end"\t")print("\n…

第64天:服务攻防-框架安全CVE复现Apache ShiroApache Solr

目录 思维导图 案例一&#xff1a;Apache Shiro-组件框架安全 shiro反序列化 cve_2016_4437 CVE-2020-17523 CVE-2020-1957 案例二&#xff1a;Apache Solr-组件框架安全 远程命令执行 RCE&#xff08;CVE-2017-12629&#xff09; 任意文件读取 AND 命令执行&#xff08…