Day03 | 链表理论基础、leetcode203. 移除链表元素、leetcode707. 设计链表、leetcode206. 反转链表

Day03

  • 链表理论基础
    • 链表的类型
      • 单链表
      • 双链表
      • 循环链表
    • 链表的存储方式
    • 链表的定义
    • 链表的操作
      • 删除节点
      • 添加节点
    • 性能分析
  • leetcode203. 移除链表元素
  • leetcode707. 设计链表
  • leetcode206. 反转链表

链表理论基础

链表的类型

单链表

链表是一种通过指针串联在一起的线性结构,每一个节点由两部分组成,一个是数据域一个是指针域(存放指向下一个节点的指针),最后一个节点的指针域指向null(空指针的意思)。
链表的入口节点称为链表的头结点也就是head。
如图所示:
单链表

双链表

双链表:每一个节点有两个指针域,一个指向下一个节点,一个指向上一个节点。
双链表 既可以向前查询也可以向后查询。
如图所示:
双链表

循环链表

循环链表,就是链表首尾相连。
循环链表可以用来解决约瑟夫环问题。
循环链表

链表的存储方式

数组是在内存中是连续分布的,但是链表在内存中可不是连续分布的。
链表是通过指针域的指针链接在内存中各个节点。
所以链表中的节点在内存中不是连续分布的 ,而是散乱分布在内存中的某地址上,分配机制取决于操作系统的内存管理。
如图所示:
链表的存储方式
这个链表起始节点为2, 终止节点为7, 各个节点分布在内存的不同地址空间上,通过指针串联在一起。

链表的定义

手写链表

// 单链表
public class ListNode {// 节点的值int val;// 下一个节点ListNode next;// 节点的构造函数(无参)public ListNode() {}// 节点的构造函数(有一个参数)public ListNode(int val) {this.val = val;}// 节点的构造函数(有两个参数)public ListNode(int val, ListNode next) {this.val = val;this.next = next;}
}

链表的操作

删除节点

删除D节点,如图所示:
删除节点
这里只需要将C节点的next指针指向E节点就可以了。
Java、Python有自己的内存回收机制,不用自己手动释放这个D节点内存。

添加节点

添加F节点,如图所示:
添加节点
可以看出链表的增添和删除都是O(1)操作,也不会影响到其他节点。
但是要注意,要是删除第五个节点,需要从头节点查找到第四个节点通过next指针进行删除操作,查找的时间复杂度是O(n)。

性能分析

链表的特性和数组的特性进行一个对比,如图所示:
性能分析
数组在定义的时候,长度就是固定的,如果想改动数组的长度,就需要重新定义一个新的数组。
链表的长度可以是不固定的,并且可以动态增删, 适合数据量不固定,频繁增删,较少查询的场景。

leetcode203. 移除链表元素

这题没按照随想录的做法来实现,一开始不知道怎么在本地IDE上创建链表,然后问了下ChatGPT就知道怎么创建链表并赋值的,下面有我IDE的代码。
注意点:

  1. 构造并赋值一个单链表/双链表,这需要熟记于心;
  2. 遍历链表每个节点前,需要弄清楚所有特殊情况,提前做好特判操作(排除空链表、头结点值为val等特殊情况);
  3. 遍历链表时,比较的是当前节点的下一个节点的值(cur.next.val),类似于指针,目的是便于进行删除或添加的操作;
// 构造一个单链表
class ListNode {// 节点的值int val;// 下一个节点ListNode next;// 节点的构造函数(1个参数)public ListNode(int val) {this.val = val;this.next = null;}
}public class leetcode203 {public static ListNode removeElements(ListNode head, int val) {// 特判:如果头节点的值等于待删除的值,则直接跳到下一个节点while (head != null && head.val == val) {head = head.next;}// 特判:如果头节点的值为空(即待遍历的链表为空链表),则直接返回nullif (head == null) {return null;}// 然后再从头开始遍历,每次判断下一个节点的值是否与待删除值相等ListNode cur = head;while (cur != null && cur.next != null) {if (cur.next.val == val) {cur.next = cur.next.next;} else {cur = cur.next;}}return head;}// 在main方法里调用public static void main(String[] args) {// 定义题目示例的链表 head//int[] nums = {1,2,6,3,4,5,6};//int[] nums = {};int[] nums = {6,6,6,6};ListNode head = new ListNode(nums[0]);ListNode cur = head;for (int i = 1; i < nums.length; i++) {cur.next = new ListNode(nums[i]);cur = cur.next;}int val = 6;// 调用函数head = removeElements(head, val);// 输出链表cur = head;while (cur != null) {System.out.print(cur.val + " ");cur = cur.next;}}
}

用python二刷,原本在本地IDE上写的,ACM模式,但是报错了,不知道如何解决,就在力扣上写了
递归法:

class Solution:def removeElements(self, head: Optional[ListNode], val: int) -> Optional[ListNode]:# 创建虚拟头部节点以简化删除过程dummy_head = ListNode()dummy_head.next = head# 遍历列表并删除值为val的节点cur = dummy_headwhile cur.next:if cur.next.val == val:cur.next = cur.next.nextelse:cur = cur.nextreturn dummy_head.next

leetcode707. 设计链表

这题做得蛮久的,主要在于深入理解链表的各种基础操作,也就是设计链表的五个接口:

  • int get(int index):获取链表第 index 个节点的数值
  • void addAtHead(int val):在链表的最前面插入一个节点
  • void addAtTail(int val):在链表的最后面插入一个节点
  • void addAtIndex(int index, int val):在链表第index个节点前面插入一个节点
  • void deleteAtIndex(int index):删除链表的第index个节点

这里建议一边写代码的时候一边在草稿纸上画图来理解,比如我就在写获取、插入和删除操作的代码那时候画了一个链表的结构图来理解,方便理解怎么找到第index个节点以及其前驱节点。

还有在链表的头节点前画了个虚拟节点dummyHead = 0,可以时刻提醒我一开始构造链表时有个虚拟节点需要注意,并方便我在写插入操作的代码时能很好地理解如何在头节点前添加一个节点,形成新头节点;还在尾节点后画了个null“节点”,表示尾节点指向null“节点”,以便我在写插入操作的代码时能很好地理解如何在尾节点后添加一个节点,形成新尾节点。

注意点:

  1. 初始化链表的操作也要熟悉;size, head
  2. 虚拟头节点,时刻注意;
  3. 写一个接口时可以调用别的接口(比如addAtHead和addAtTail接口里调用了addAtIndex接口),能提高代码复用性,降低代码冗余;
  4. 前驱节点pre,插入和删除操作都要用到;
  5. 边写代码边画图,事半功倍。
// 单链表
class ListNode {int val;ListNode next;ListNode(int val) {this.val = val;this.next = null;}
}class MyLinkedList {// 定义存储链表元素的个数int size;// 定义虚拟头结点(名字不重要,dummyHead或者head都行)ListNode head;// 初始化链表public MyLinkedList() {size = 0;head = new ListNode(0);}// 获取第index个节点的数值,注意index是从0开始的,第0个节点就是头结点public int get(int index) {// 如果 index 非法,返回 -1if (index < 0 || index >= size) {return -1;}ListNode cur = head;// 因为包含一个虚拟头节点head,所以是要查找第 index+1 个节点for (int i = 0; i <= index; i++) {cur = cur.next;}return cur.val;}// 在链表最前面插入一个节点,等价于在第0个元素前添加public void addAtHead(int val) {addAtIndex(0, val);}// 在链表最后面插入一个节点,等价于在(末尾+1)个元素前添加public void addAtTail(int val) {addAtIndex(size, val);}// 在第 index 个节点之前插入一个新节点// 如果 index 为 0,则说明新插入的节点为链表的新头节点// 如果 index 为链表的长度 size,则说明新插入的节点为链表的新尾结点public void addAtIndex(int index, int val) {// 如果 index 大于链表的长度,则返回空if (index > size) {return;}// 如果 index 小于 0,等同于在头部插入节点(先将index赋值为0)if (index < 0) {index = 0;}// 此时确定要插入一个节点了,链表长度先自增一个单位size++;// 找到要插入节点的前驱节点(记得有个虚拟头结点)ListNode pre = head;for (int i = 0; i < index; i++) {pre = pre.next;}// 插入操作:先让插入节点指向前驱节点的下一个节点,再让前驱节点指向插入节点ListNode toAdd = new ListNode(val);toAdd.next = pre.next;pre.next = toAdd;}// 删除第 index 个节点public void deleteAtIndex(int index) {// 如果 index 小于 0 或者大于等于链表的长度,则直接返回if (index < 0 || index >= size) {return;}// 此时确定要删除一个节点了,链表长度先自减一个单位size--;// 找到要插入节点的前驱节点(记得有个虚拟头结点)ListNode pre = head;for (int i = 0; i < index; i++) {pre = pre.next;}// 删除操作pre.next = pre.next.next;}
}

leetcode206. 反转链表

这题也是思路一下就有,但不知道具体如何实现,还是写代码少了,应该每天都写算法题的,前段时间由于实验室科研项目导致一直没看算法题。

注意点:
1.首先应该申请节点:pre(初始化为null) 和 cur(指向头结点),以及临时变量 tmp(保存cur.next);
2. 循环逻辑要弄清晰,最好在一旁画个草稿图帮助自己理解,运行一两个循环试试看;
3. 最后的循环结束条件以及返回值也要弄清楚,建议画图理解;
4. 个人感觉循环中的操作过程类似于数组中的交换元素,可以做类比学习。

class Solution {// 双指针法public ListNode reverseList(ListNode head) {// 申请节点: pre 和 cur, pre 指向 nullListNode pre = null;ListNode cur = head;ListNode tmp = null;// 循环遍历while (cur != null) {// 记录当前节点的下一个节点tmp = cur.next;// 然后将当前节点指向 precur.next = pre;// pre 和 cur 节点都前进一位pre = cur;cur = tmp;}return pre;}
}

递归的两个条件:
终止条件是当前节点或者下一个节点==null
在函数内部,改变节点的指向,也就是 head 的下一个节点指向 head 递归函数那句。

递归法中,我们应该关心的主要有三点:
返回值:指向改变的节点,也就是每次递归的最后一个节点
调用单元f(x)做了什么:改变节点head的指向(调用单元f(x):head.next 指向 head,也就是最后一个节点cur指向其前一个节点head)
终止条件:head 为空指针或者 head.next 为空指针,也就是当前为空或者下一个节点为空;

class Solution {public ListNode reverseList(ListNode head) {// 递归终止条件: 当前为空,或者下一个节点为空if (head == null || head.next == null) {return head;}// 进行递归(cur是返回值:指向改变的节点)ListNode cur = reverseList(head.next);// 这里进行节点指向改变(调用单元f(x):head.next 指向 head,也就是最后一个节点cur指向其前一个节点head)head.next.next = head;// 防止链表循环,需要将head.next设置为空head.next = null;// 返回节点(每层递归函数都返回cur,也就是最后一个节点)return cur;}
}

用python二刷,在本地IDE上写,ACM模式
递归法:

# Definition for a single linked list
class ListNode:def __init__(self, val, next=None):self.val = valself.next = next# 构建单链表(利用递归)
def build_linked_list(arr):if not arr:return Nonehead = ListNode(arr[0])head.next = build_linked_list(arr[1:])return head#
nums = [1,2,3,4,5]
head = build_linked_list(nums)def reverseList(head: ListNode) -> ListNode:# 递归终止条件是当前为空,或者下一个节点为空if (head == None or head.next == None):return head# 这里的cur就是最后一个节点cur = reverseList(head.next)# 如果链表是 1->2->3->4->5,那么此时的cur就是5# 而head是4,head的下一个是5,下下一个是空# 所以head.next.next 就是5->4head.next.next = head# 防止链表循环,需要将head.next设置为空head.next = None# 每层递归函数都返回cur,也就是最后一个节点return curprint(reverseList(head))

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

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

相关文章

超级炫酷的AI绘图工具—MidJourney详细使用教程

&#x1f3c6; 文章目标&#xff1a;了解学习AI绘图工具—MidJourney详细使用教程&#xff0c;顺应潮流。 &#x1f340; 超级炫酷的AI绘图工具—MidJourney详细使用教程 ✅ 创作者&#xff1a;Jay… &#x1f389; 个人主页&#xff1a;Jay的个人主页 &#x1f341; 展望&…

7个令人惊艳的 ChatGPT 项目,必须分享

文章目录 一、ChartGPT是什么二、ChatGPT 让你回家种田三、GitHub 上较为活跃的&#xff0c;开源项目3.1、Copilot 开源解决方案3.2、让命令行也能用上 ChatGPT3.3、飞书 GPT3.4、最美的GPT管理界面3.5、ChatPDF 开源方案3.6、VSCode 智能插件3.7 、数据指北Ai 大家好&#xff…

Echarts绘图技巧

目录 Echarts是什么(ChatGPT) 代码部分 引入工具箱 标题、图例 调节横纵坐标值、名字的字体 数据显示问题 总结 Echarts是什么(ChatGPT) Echarts是一个开源的Javascript图表库&#xff0c;用于基于Web的数据可视化。它可以用于创建各种类型的图表&#xff0c;如折线图、饼…

先用ChatGPT革自己的命,然后干翻所有人!微软要“梭哈”了!

‍数据智能产业创新服务媒体 ——聚焦数智 改变商业 现如今&#xff0c;生成式AI刮起的大风可谓是一直都在天上盘旋&#xff0c;ChatGPT这把火也烧的越来越旺。各公司都在追ChatGPT这个热点&#xff0c;例如&#xff1a;百度还没“出生”便先“出名”的文心一言&#xff0c;微…

2022年语音合成(TTS)和语音识别(ASR)年度总结

论文统计每月更新一次&#xff0c;主要跟踪语音合成和语音识别的发展状况(很多文章都是在会议后才发出&#xff0c;但不影响统计。统计过程难免存在疏漏&#xff0c;因此统计结果仅供参考。所有文章语音合成领域统计列表请访问http://yqli.tech/page/tts_paper.html&#xff0c…

ControlNet多重控制功能推出,AI绘画进入导演时代!

目录 一、“不会开发游戏的AI工具制作者不是好博士” 二、ControlNet出现的背景 三、什么是ControlNet&#xff1f; 四、「神采 Prome AI」的诞生 五、总结 去年DALLE2&#xff0c;Stable Diffusion等文-图底层大模型发布带动了应用层的发展&#xff0c;出现了一大批爆款产…

阿里类ChatGPT产品正在内测;谷歌AI聊天机器人翻车,市值缩水逾7000亿元;Android 14开发者预览版发布|极客头条...

「极客头条」—— 技术人员的新闻圈&#xff01; CSDN 的读者朋友们早上好哇&#xff0c;「极客头条」来啦&#xff0c;快来看今天都有哪些值得我们技术人关注的重要新闻吧。 整理 | 梦依丹 出品 | CSDN&#xff08;ID&#xff1a;CSDNnews&#xff09; 一分钟速览新闻点&#…

InsCode AI 创作助手:源于 CSDN 的 AI 创作助手,不一样的创作体验

文章目录 &#x1f4cb;前言&#x1f3af;AIGC 时代的产物&#x1f3af;InsCode AI 创作助手体验&#x1f3af;一些感受和建议&#x1f9e9;感受&#x1f9e9;建议&#xff08;个人看法&#xff09; &#x1f4dd;最后 &#x1f4cb;前言 是的没错&#xff0c;CSDN AI 写作助手…

零基础部署chatglm

目录 ubuntu部署 1. 下载安装anaconda3 2. 创建并虚拟环境 3. 下载安装chatglm 4. 修改代码&#xff0c;减少gpu使用&#xff0c;目前使用6G显存 5.启动web服务 windows部署 1. 下载安装anaconda3 2. 创建并虚拟环境 3. 下载安装chatglm 4. 修改代码&#xff0c;减少…

chatgpt赋能Python-python3虚拟环境搭建

Python3虚拟环境搭建&#xff1a;介绍和步骤 Python是一门非常强大的编程语言&#xff0c;因此在许多不同类型的项目中都广泛使用。但是&#xff0c;不同项目可能需要使用不同版本的Python库和依赖项。这就是使用Python的虚拟环境的重要性&#xff0c;可以避免不同项目之间的冲…

吴恩达《ChatGPT Prompt Engineering for Developers》学习笔记

来自&#xff1a;口仆 进NLP群—>加入NLP交流群 本笔记是 deeplearning.ai 最近推出的短期课程《ChatGPT Prompt Engineering for Developers》的学习总结。 1 引言 总的来说&#xff0c;当前有两类大语言模型&#xff08;LLM&#xff09;&#xff1a;「基础 LLM」 和「指令…

深度学习(20):nerf论文翻译与学习

目录 1 Introduction 2 Related Work 3 Neural Radiance Field Scene Representation 4 Volume Rendering with Radiance Fields 5 Optimizing a Neural Radiance Field 5.1 Positional encoding 5.2 Hierarchical volume sampling 5.3 Implementation details 6 Resu…

软件测试相关的一些笔记(七拼八凑笔记)

小插曲 IT行业职位简称 PD---product director&#xff08;产品总监/部门经理&#xff09;比项目经理级别高 PM---Project Management &#xff08;项目经理&#xff09; PL---Project Leader项目组长 PG---Prograer 程序员 SA---SystemAnalyst 系统分析师 QA--- QUALITY ASSU…

VALSE2023-内容总结(正在更新)

博文为精选内容&#xff0c;完整ppt请留言索取 一周内更新完毕&#xff0c;敬请期待 2023年度视觉与学习青年学者研讨会 (Vision And Learning SEminar, VALSE)于6月10日至12日在无锡太湖国际博览中心召开&#xff0c;由中国人工智能学会、中国图象图形学学会主办&#xff0c;…

特斯拉今天拉了,马斯克迟到半小时,一开口市值蒸发2048亿元

编辑部 发自 凹非寺量子位 | 公众号 QbitAI 啥也没有&#xff01; 17万新车、HW4.0、4D雷达……在大伙儿万众期待的特斯拉投资者日活动上&#xff0c;统统都没有&#xff01; 而且马斯克还迟到整整半小时&#xff0c;一张口股价就跌了1.43%&#xff0c;市值直接蒸发约2048亿元&…

【Shader Graph】SmoothStep节点详解及其应用

目录 一、SmoothStep函数 二、基础图像 情况一&#xff1a;t1 > t2 情况二&#xff1a;t1 < t2 三、两个SmoothStep函数相减的图像 1&#xff09;SmoothStep(t1&#xff0c;t2&#xff0c;x) - SmoothStep(t2&#xff0c;t3&#xff0c;x) 2&#xff09;SmoothS…

【Unity_Input System】Input System新输入系统(一)

目录 一、导入Input System包 二、使用方式1&#xff1a;直接从输入设备对应类中获取输入 三、使用方式2&#xff1a;用代码创建InputAction获取输入 四、使用方式3&#xff1a;用Player Input组件获取输入 五、使用方式4&#xff1a;用Input Action Asset生成C#代码获取输…

Echarts的地图实现拖拽缩放同步功能(解决多层geo缩放、拖动卡顿问题)

项目场景&#xff1a; 大屏项目显示云南省3D的地图&#xff0c;可拖拽缩放、地图打点、点击图标弹框等等功能 问题描述 多图层拖拽时会上下层会分离&#xff0c;延迟卡顿 原因分析&#xff1a; 1、拖拽时不同图层的中心坐标没有保持一致&#xff0c; 2、卡顿是数据更新动画时…

php编写年历流程图,使用PHP怎么编写一个万年历功能

使用PHP怎么编写一个万年历功能 发布时间&#xff1a;2020-12-25 14:27:13 来源&#xff1a;亿速云 阅读&#xff1a;94 作者&#xff1a;Leah 这篇文章将为大家详细讲解有关使用PHP怎么编写一个万年历功能&#xff0c;文章内容质量较高&#xff0c;因此小编分享给大家做个参考…

mysql审计audit插件_MySQL审计工具Audit插件使用

MySQL审计工具Audit插件使用一、介绍MySQL AUDIT MySQL AUDIT Plugin是一个 MySQL安全审计插件&#xff0c;由McAfee提供&#xff0c;设计强调安全性和审计能力。该插件可用作独立审计解决方案&#xff0c;或配置为数据传送给外部监测工具。支持版本为MySQL (5.1, 5.5, 5.6, 5.…