LeetCode.707设计链表(链表相关操作一篇就够了)
LeetCode.707设计链表
- 1.问题描述
- 2.解题思路
- 3.代码
1.问题描述
你可以选择使用单链表或者双链表,设计并实现自己的链表。
单链表中的节点应该具备两个属性:val 和 next 。val 是当前节点的值,next 是指向下一个节点的指针/引用。
如果是双向链表,则还需要属性 prev 以指示链表中的上一个节点。假设链表中的所有节点下标从 0 开始。
实现 MyLinkedList 类:
MyLinkedList()初始化MyLinkedList对象。int get(int index)获取链表中下标为index的节点的值。如果下标无效,则返回-1。void addAtHead(int val)将一个值为val的节点插入到链表中第一个元素之前。在插入完成后,新节点会成为链表的第一个节点。void addAtTail(int val)将一个值为val的节点追加到链表中作为链表的最后一个元素。void addAtIndex(int index, int val)将一个值为val的节点插入到链表中下标为index的节点之前。如果index等于链表的长度,那么该节点会被追加到链表的末尾。如果index比长度更大,该节点将 不会插入 到链表中。void deleteAtIndex(int index)如果下标有效,则删除链表中下标为index的节点。
示例:
输入
["MyLinkedList", "addAtHead", "addAtTail", "addAtIndex", "get", "deleteAtIndex", "get"]
[[], [1], [3], [1, 2], [1], [1], [1]]
输出
[null, null, null, null, 2, null, 3]解释
MyLinkedList myLinkedList = new MyLinkedList();
myLinkedList.addAtHead(1);
myLinkedList.addAtTail(3);
myLinkedList.addAtIndex(1, 2); // 链表变为 1->2->3
myLinkedList.get(1); // 返回 2
myLinkedList.deleteAtIndex(1); // 现在,链表变为 1->3
myLinkedList.get(1); // 返回 3
提示:
0 <= index, val <= 1000- 请不要使用内置的 LinkedList 库。
- 调用
get、addAtHead、addAtTail、addAtIndex和deleteAtIndex的次数不超过2000。
2.解题思路
使用虚拟头结点,这道题目设计链表的五个接口:
-
获取链表第index个节点的数值:先判断index是否合法,
index < 0 || index > (size - 1)便不合法。定义一个指针,遍历:如果直接操作头结点,头结点值被改了,无法返回头结点。ListNode* cur = dummyHead->next; while(index) {cur = cur->next;index--; } return cur->val;为何临时指针指针指向
dummyHead->next以及循环如何写,可带入一个节点进行验证。如果index=0,那么相当于获得原始头结点的值,while循环直接跳过之后,return确实合理,那么while循环以及临时指针的指向便没问题。 -
在链表的最前面插入一个节点:在虚拟头结点和头结点之间插入新节点就好了
newNode->next = dummyHead->next; dummyHead->next = newNode;注意以上顺序不可变
-
在链表的最后面插入一个节点:cur节点必须指向最后一个节点。怎么找尾结点?
while(cur->next != nullptr) {cur = cur->next; //只要不为空,就一直执行这句话 } -
在链表第index个节点前面插入一个节点
如果要在第index个节点钱插入,必须保证第index个节点为
cur->next,也就是cur指向第index个节点的前一位。只有知道操作节点的前一个节点,才能进行后续操作。ListNode* cur = dummyHead; while(index) {cur = cur->next;index--; } newNode->next = cur->next; cur->next = newNode; size++;检验对否,可随便代入一个节点便知道。如果index=0,那么while循环不操作等等进行分析。
-
删除链表的第index个节点
同理,删除第index个节点,必须知道前一个节点的指针。必须保证第index个节点为
cur->nextListNode* cur = dummyHead; while(index) {cur = cur->next;index--; } ListNode* tmp = cur->next; cur->next = cur->next->next; delete tmp; tmp = nullptr; size--;delete命令指示释放了tmp指针原本所指的那部分内存,被delete后的指针tmp的值(地址)并非就是NULL,而是随机值。也就是被delete后,如果不再加上一句tmp=nullptr,tmp会成为乱指的野指针,如果之后的程序不小心使用了tmp,会指向难以预想的内存空间。
3.代码
C++:
class MyLinkedList {public:struct ListNode {int val;ListNode* next;ListNode(int x): val(x), next(NULL) {}//构造函数};MyLinkedList() {dummyHead = new ListNode(0); // 虚拟头节点size = 0;// 初始化单链表长度}// 获取链表中第 index个节点的值:// 获取到第index个节点数值,如果index是非法数值直接返回-1,// 注意index是从0开始的,第0个节点就是头结点int get(int index) {if(index < 0 || index > (size - 1)) { // 如果 index 不合理,返回 -1return -1;}ListNode* cur = dummyHead->next; //创建一个指针 cur,指向虚拟头结点的下一个节点。//循环遍历链表,移动 cur 指针到第 index 个节点处。while(index) {cur = cur->next;index--;}return cur->val;}//在链表头部插入新节点void addAtHead(int val) {//创建一个新节点ListNode* newNode = new ListNode(val);//注意以下两句话的顺序newNode->next = dummyHead->next;dummyHead->next = newNode;// 链表大小加1。size++;}//在链表尾部添加新节点void addAtTail(int val) {//创建一个新节点ListNode* newNode = new ListNode(val);//创建一个指针 cur,指向虚拟头结点ListNode* cur = dummyHead;//循环遍历链表,移动 cur 指针到最后一个节点处while(cur->next != nullptr) {cur = cur->next;}//将最后一个节点的下一个节点指向新节点。cur->next = newNode;size++;}//在指定位置插入新节点// 在第index个节点之前插入一个新节点,例如index为0,那么新插入的节点为链表的新头节点。// 如果index 等于链表的长度,则说明是新插入的节点为链表的尾结点// 如果index大于链表的长度,则返回空// 如果index小于0,则在头部插入节点void addAtIndex(int index, int val) {if(index > size) return;//如果 index 大于链表的大小,则直接返回。if(index < 0) index = 0;//如果 index 小于0,则将其设置为0。ListNode* newNode = new ListNode(val);//创建一个新节点,并将其值设置为 val。ListNode* cur = dummyHead;while(index) {cur = cur->next;index--;}newNode->next = cur->next;cur->next = newNode;size++;}// 删除第index个节点,如果index 大于等于链表的长度,直接return,注意index是从0开始的void deleteAtIndex(int index) {//判断 index 是否合法,如果不合法,直接返回。if(index >= size ||index < 0) {return;}//创建一个指针 cur,指向虚拟头结点。ListNode* cur = dummyHead;while(index) {cur = cur->next;index--;}ListNode* tmp = cur->next; // 创建一个临时节点指向即将删除的节点cur->next = cur->next->next;// 当前节点指针指向待删除节点的下一个节点delete tmp;// 释放内存//delete命令指示释放了tmp指针原本所指的那部分内存,//被delete后的指针tmp的值(地址)并非就是NULL,而是随机值。也就是被delete后,//如果不再加上一句tmp=nullptr,tmp会成为乱指的野指针//如果之后的程序不小心使用了tmp,会指向难以预想的内存空间tmp = nullptr;size--;}void printLinkedList() {ListNode* cur = dummyHead;while (cur->next != nullptr) {cout << cur->next->val << " ";cur = cur->next;}cout << endl;}private:int size;ListNode* dummyHead;
};
python:单链表
class ListNode:def __init__(self, val=0, next=None):self.val = valself.next = nextclass MyLinkedList:def __init__(self):self.dummy_head = ListNode()self.size = 0def get(self, index: int) -> int:if index < 0 or index >= self.size:return -1current = self.dummy_head.nextfor i in range(index):current = current.nextreturn current.valdef addAtHead(self, val: int) -> None:self.dummy_head.next = ListNode(val, self.dummy_head.next)self.size += 1def addAtTail(self, val: int) -> None:current = self.dummy_headwhile current.next:current = current.nextcurrent.next = ListNode(val)self.size += 1def addAtIndex(self, index: int, val: int) -> None:if index < 0 or index > self.size:returncurrent = self.dummy_headfor i in range(index):current = current.nextcurrent.next = ListNode(val, current.next)self.size += 1def deleteAtIndex(self, index: int) -> None:if index < 0 or index >= self.size:returncurrent = self.dummy_headfor i in range(index):current = current.nextcurrent.next = current.next.nextself.size -= 1
python:双链表
class ListNode:def __init__(self, val=0, prev=None, next=None):self.val = valself.prev = prevself.next = nextclass MyLinkedList:def __init__(self):self.head = Noneself.tail = Noneself.size = 0def get(self, index: int) -> int:if index < 0 or index >= self.size:return -1if index < self.size // 2:current = self.headfor i in range(index):current = current.nextelse:current = self.tailfor i in range(self.size - index - 1):current = current.prevreturn current.valdef addAtHead(self, val: int) -> None:new_node = ListNode(val, None, self.head)if self.head:self.head.prev = new_nodeelse:self.tail = new_nodeself.head = new_nodeself.size += 1def addAtTail(self, val: int) -> None:new_node = ListNode(val, self.tail, None)if self.tail:self.tail.next = new_nodeelse:self.head = new_nodeself.tail = new_nodeself.size += 1def addAtIndex(self, index: int, val: int) -> None:if index < 0 or index > self.size:returnif index == 0:self.addAtHead(val)elif index == self.size:self.addAtTail(val)else:if index < self.size // 2:current = self.headfor i in range(index - 1):current = current.nextelse:current = self.tailfor i in range(self.size - index):current = current.prevnew_node = ListNode(val, current, current.next)current.next.prev = new_nodecurrent.next = new_nodeself.size += 1def deleteAtIndex(self, index: int) -> None:if index < 0 or index >= self.size:returnif index == 0:self.head = self.head.nextif self.head:self.head.prev = Noneelse:self.tail = Noneelif index == self.size - 1:self.tail = self.tail.previf self.tail:self.tail.next = Noneelse:self.head = Noneelse:if index < self.size // 2:current = self.headfor i in range(index):current = current.nextelse:current = self.tailfor i in range(self.size - index - 1):current = current.prevcurrent.prev.next = current.nextcurrent.next.prev = current.prevself.size -= 1
相关文章:
LeetCode.707设计链表(链表相关操作一篇就够了)
LeetCode.707设计链表 1.问题描述2.解题思路3.代码 1.问题描述 你可以选择使用单链表或者双链表,设计并实现自己的链表。 单链表中的节点应该具备两个属性:val 和 next 。val 是当前节点的值,next 是指向下一个节点的指针/引用。 如果是双…...
图论——二部图及其算法
什么是二部图 二部图的判定 例子1 任选一个节点染成红色 红色的邻居染成蓝色 蓝色邻居染成红色 例子2 这个不是二部图 无权二部图的最大匹配...
实现简单的操作服务器和客户端(下)
一、说明 描述:本教程介绍如何使用 simple_action_client 库创建斐波那契操作客户端。此示例程序创建一个操作客户端并将目标发送到操作服务器。 内容 代码代码解释编译运行操作客户端连接服务器和客户端...
第二十章 解读PASCAL VOC2012与MS COCO数据集(工具)
PASCAL VOC2012数据集 Pascal VOC2012官网地址:http://host.robots.ox.ac.uk/pascal/VOC/voc2012/ 官方发表关于介绍数据集的文章 《The PASCALVisual Object Classes Challenge: A Retrospective》:http://host.robots.ox.ac.uk/pascal/VOC/pubs/everi…...
FreeRTOS列表和列表项
目录 列表和列表项 关于列表的一些操作 初始化列表 初始化列表项 列表插入列表项 列表项末尾插入 重点 pxIndex指向的是什么 xItemValue存的是什么 vListInsertEnd()的插入位置 List的头尾在哪里? 通用链表的三种实现方式 方法一 方法二 方法三 总结 Fre…...
【go语言实现一个webSocket的一个demo】
go语言实现一个webSocket的一个demo 前端代码 <html lang"zh-CN"><head></head><body> <script type"text/javascript">// header(Access-Control-Allow-Origin:*);var sock null;var wsuri "ws://127.0.0.1:9999&…...
es6字符串模板之标签化模板
es6字符串模板 我们经常搞前端开发工作的都会用到。它可以保留字符串换行格式,还能接受变量。这个给前端的字符串拼接带来了非常大的方便。但是还有一种用法可能是我们平时还是没有怎么用到的。 styled-components 在项目中熟悉使用react的童鞋可能会用过styled-…...
opencv入门1.1:从视频或摄像头读取图像
cv::VideoCapture是 OpenCV 中用于从视频文件或摄像头捕获图像帧的类。它提供了各种方法和函数,用于读取和处理视频数据。 以下是对 cv::VideoCapture类的详细解释和说明: 1. 打开视频源 为了使用 cv::VideoCapture,我们首先需要打开一个视…...
【数据中台】开源项目(1)-LarkMidTable
LarkMidTable 是一站式开源的数据中台,实现中台的 基础建设,数据治理,数据开发,监控告警,数据服务,数据的可视化,实现高效赋能数据前台并提供数据服务的产品。 系统演示地址 : www.l…...
VUE简易购物车程序
目录 效果预览图 完整代码 效果预览图 完整代码 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>…...
如何清除redis缓存?
首先进入redis安装目录 当前目录下执行CMD命令(shift 右键 -> 选择 ‘在此处打开Powershell窗口’ ) 执行 redis-cli.exe -h 127.0.0.1 -p 6379flushall...
接收网络包的过程——从硬件网卡解析到IP层
当一些网络包到来触发了中断,内核处理完这些网络包之后,我们可以先进入主动轮询 poll 网卡的方式,主动去接收到来的网络包。如果一直有,就一直处理,等处理告一段落,就返回干其他的事情。当再有下一批网络包…...
正则化与正则剪枝
写在前面:本博客仅作记录学习之用,部分图片来自网络,如需引用请注明出处,同时如有侵犯您的权益,请联系删除! 文章目录 引言正则化为什么会过拟合拉格朗日与正则化梯度衰减与正则化 应用解决过拟合网络剪枝 …...
Element-Plus 图标自动导入
🚀 作者主页: 有来技术 🔥 开源项目: youlai-mall 🍃 vue3-element-admin 🍃 youlai-boot 🌺 仓库主页: Gitee 💫 Github 💫 GitCode 💖 欢迎点赞…...
关于DCDC电源中的PWM与PFM
在开关电源DCDC中,我们经常会听到PWM模式与PFM模式。 关于,这两种模式,小编在之前的文章中,做过简单的描述。今天就来针对性的就这两种模式展开讲讲。 PWM:脉冲宽度调制,即频率不变,不断调整脉…...
S25FL系列FLASH读写的FPGA实现
文章目录 实现思路具体实现子模块实现top模块 测试Something 实现思路 建议读者先对 S25FL-S 系列 FLASH 进行了解,我之前的博文中有详细介绍。 笔者的芯片具体型号为 S25FL256SAGNFI00,存储容量 256Mb,增强高性能 EHPLC,4KB 与 6…...
一次【自定义编辑器功能脚本】【调用时内存爆仓】事故排查
一 、事故描述 我有一个需求:在工程文件中找得到所有的图片(Texture 2D),然后把WebGL发布打包时的图片压缩规则进行修改。 项目中有图片2千多张,其中2k分辨率的图片上百张,当我右键进行批量处理的时候&…...
【STM32单片机】简易计算器设计
文章目录 一、功能简介二、软件设计三、实验现象联系作者 一、功能简介 本项目使用STM32F103C8T6单片机控制器,使用动态数码管模块、矩阵按键、蜂鸣器模块等。 主要功能: 系统运行后,数码管默认显示0,输入对应的操作数进行四则运…...
【详解二叉树】
🌠作者:TheMythWS. 🎇座右铭:不走心的努力都是在敷衍自己,让自己所做的选择,熠熠发光。 目录 树形结构 概念 树的示意图 树的基本术语 树的表示 树的应用 二叉树(重点) 二叉树的定义 二叉树的五…...
【Amazon】在Amazon EKS集群中安装部署最小化KubeSphere容器平台
文章目录 一、准备工作二、部署 KubeSphere三、访问 KubeSphere 控制台四、安装Amazon EBS CSI 驱动程序4.1 集群IAM角色建立并赋予权限4.2 安装 Helm Kubernetes 包管理器4.3 安装Amazon EBS CSI 驱动程序 五、常见问题六、参考链接 一、准备工作 Kubernetes 版本必须为&…...
Appium+python自动化(十六)- ADB命令
简介 Android 调试桥(adb)是多种用途的工具,该工具可以帮助你你管理设备或模拟器 的状态。 adb ( Android Debug Bridge)是一个通用命令行工具,其允许您与模拟器实例或连接的 Android 设备进行通信。它可为各种设备操作提供便利,如安装和调试…...
工业安全零事故的智能守护者:一体化AI智能安防平台
前言: 通过AI视觉技术,为船厂提供全面的安全监控解决方案,涵盖交通违规检测、起重机轨道安全、非法入侵检测、盗窃防范、安全规范执行监控等多个方面,能够实现对应负责人反馈机制,并最终实现数据的统计报表。提升船厂…...
前端导出带有合并单元格的列表
// 导出async function exportExcel(fileName "共识调整.xlsx") {// 所有数据const exportData await getAllMainData();// 表头内容let fitstTitleList [];const secondTitleList [];allColumns.value.forEach(column > {if (!column.children) {fitstTitleL…...
1688商品列表API与其他数据源的对接思路
将1688商品列表API与其他数据源对接时,需结合业务场景设计数据流转链路,重点关注数据格式兼容性、接口调用频率控制及数据一致性维护。以下是具体对接思路及关键技术点: 一、核心对接场景与目标 商品数据同步 场景:将1688商品信息…...
鸿蒙中用HarmonyOS SDK应用服务 HarmonyOS5开发一个医院挂号小程序
一、开发准备 环境搭建: 安装DevEco Studio 3.0或更高版本配置HarmonyOS SDK申请开发者账号 项目创建: File > New > Create Project > Application (选择"Empty Ability") 二、核心功能实现 1. 医院科室展示 /…...
C++中string流知识详解和示例
一、概览与类体系 C 提供三种基于内存字符串的流,定义在 <sstream> 中: std::istringstream:输入流,从已有字符串中读取并解析。std::ostringstream:输出流,向内部缓冲区写入内容,最终取…...
浪潮交换机配置track检测实现高速公路收费网络主备切换NQA
浪潮交换机track配置 项目背景高速网络拓扑网络情况分析通信线路收费网络路由 收费汇聚交换机相应配置收费汇聚track配置 项目背景 在实施省内一条高速公路时遇到的需求,本次涉及的主要是收费汇聚交换机的配置,浪潮网络设备在高速项目很少,通…...
保姆级教程:在无网络无显卡的Windows电脑的vscode本地部署deepseek
文章目录 1 前言2 部署流程2.1 准备工作2.2 Ollama2.2.1 使用有网络的电脑下载Ollama2.2.2 安装Ollama(有网络的电脑)2.2.3 安装Ollama(无网络的电脑)2.2.4 安装验证2.2.5 修改大模型安装位置2.2.6 下载Deepseek模型 2.3 将deepse…...
mac 安装homebrew (nvm 及git)
mac 安装nvm 及git 万恶之源 mac 安装这些东西离不开Xcode。及homebrew 一、先说安装git步骤 通用: 方法一:使用 Homebrew 安装 Git(推荐) 步骤如下:打开终端(Terminal.app) 1.安装 Homebrew…...
【Android】Android 开发 ADB 常用指令
查看当前连接的设备 adb devices 连接设备 adb connect 设备IP 断开已连接的设备 adb disconnect 设备IP 安装应用 adb install 安装包的路径 卸载应用 adb uninstall 应用包名 查看已安装的应用包名 adb shell pm list packages 查看已安装的第三方应用包名 adb shell pm list…...
