leetcode 707. 设计链表

一.题目描述

你可以选择使用单链表或者双链表,设计并实现自己的链表。

单链表中的节点应该具备两个属性: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

二.思路分析

1.大体思路

先在类里面创建结构体,制造链表所包含的要求,再分析每一个函数所要求的,最后析构即可。

2.细节

(1)结构体的设置

设置结构体的时候,要设置一个有参构造,以应对新的ListNode的插入,同时要在结构体外部设置一个头指针head和用来表示链表大小的size。

(2)int get部分

首先要注意的是,判断index是否合法的条件是<0和>=size,这里的>=size是因为我们的链表是从0开始末尾的那个链表部分的序号是size-1,接下来就是用cur指针便利了.

(3)void addAtHead部分

这里要注意的是这两行代码不能颠倒顺序,应为颠倒后newNode->next指向不了你所需的先前的head.

 newNode->next=head; head=newNode;

(4)void addAtTail部分

首先要判断是否为空链表,若为空则,直接使head指向newhead即可

若不为空,则让cur遍历到链表最后端即可。

(5)void addAtIndex部分

首先要判断是否合法,同(2)部分,然后就是单独把头部插入和尾部插入分别单列出来,调用以上所写的函数即可,没必要再写一遍,中间部分正常便利即可

或者整个函数用dummyhead实现也可以:

 void addAtIndex(int index, int val) { if (index < 0 || index > size) { return; } ListNode dummy(0); dummy.next=head; ListNode* newNode=new ListNode(val); ListNode* cur=&dummy; while(index--) { cur=cur->next; } newNode->next=cur->next; cur->next=newNode; head=dummy.next; size++; }

这里要注意的是,用dummy时,可能用例子把head所指的链表更新了,所以在倒数第二行有一句head=dummy.next,更新表头,这部分可以完美替换“三”中的相应部分。

(6)void deleteAtIndex部分

可以把头部的情况单独写一下,再用以上相同的方法遍历即可

后者用dummy也可以:

 void deleteAtIndex(int index) { if(index<0||index>=size) return; ListNode dummy(0); dummy.next=head; ListNode* cur=&dummy; while(index--) { cur=cur->next; } ListNode* temp = cur->next; cur->next=cur->next->next; delete temp; head=dummy.next; size--; }

这里delete是防止内存泄漏,为了通过的话,也可以不用

(7)~MyLinkedList部分

从head开始遍历,释放链表,因为这里cur是用来遍历的,所以,要用temp来过度一下,可写可不写,随意,严谨就写,不写也能通过

三.代码实现

class MyLinkedList { private: struct ListNode { int val; ListNode* next; ListNode(int x):val(x),next(nullptr){} }; ListNode* head; int size; public: MyLinkedList() { head=nullptr; size=0; } int get(int index) { if(index<0||index>=size) return -1; ListNode* cur=head; for(int i=0;i<index;i++) { cur=cur->next; } return cur->val; } void addAtHead(int val) { ListNode* newNode= new ListNode(val); newNode->next=head; head=newNode; size++; } void addAtTail(int val) { ListNode* newNode=new ListNode(val); if(head==nullptr) { head=newNode; } else { ListNode* cur=head; while(cur->next!=nullptr) { cur=cur->next; } cur->next=newNode; } size++; } void addAtIndex(int index, int val) { if(index<0||index>size) return; if(index==0) { addAtHead(val); return; } if(index==size) { addAtTail(val); return; } ListNode* cur=head; for(int i=0;i<index-1;i++) { cur=cur->next; } ListNode* newNode=new ListNode(val); newNode->next=cur->next; cur->next=newNode; size++; } void deleteAtIndex(int index) { if(index<0||index>=size) return; if(index==0) { ListNode* temp=head; head=head->next; delete temp; } else { ListNode* cur=head; for(int i=0;i<index-1;i++) { cur=cur->next; } ListNode* temp=cur->next; cur->next=cur->next->next; delete temp; } size--; } ~MyLinkedList() { ListNode* cur=head; while(cur!=nullptr) { ListNode* temp=cur; cur=cur->next; delete temp; } } };

Read more

【OpenClaw从入门到精通】第10篇:OpenClaw生产环境部署全攻略:性能优化+安全加固+监控运维(2026实测版)

【OpenClaw从入门到精通】第10篇:OpenClaw生产环境部署全攻略:性能优化+安全加固+监控运维(2026实测版)

摘要:本文聚焦OpenClaw从测试环境走向生产环境的核心痛点,围绕“性能优化、安全加固、监控运维”三大维度展开实操讲解。先明确生产环境硬件/系统选型标准,再通过硬件层资源管控、模型调度策略、缓存优化等手段提升响应速度(实测响应效率提升50%+);接着从网络、权限、数据三层构建安全防护体系,集成火山引擎安全方案拦截高危操作;最后落地TenacitOS可视化监控与Prometheus告警体系,配套完整故障排查清单和虚拟实战案例。全文所有配置、代码均经实测验证,兼顾新手入门实操性和进阶读者的生产级部署需求,帮助开发者真正实现OpenClaw从“能用”到“放心用”的跨越。 优质专栏欢迎订阅! 【DeepSeek深度应用】【Python高阶开发:AI自动化与数据工程实战】【YOLOv11工业级实战】 【机器视觉:C# + HALCON】【大模型微调实战:平民级微调技术全解】 【人工智能之深度学习】【AI 赋能:Python 人工智能应用实战】【数字孪生与仿真技术实战指南】 【AI工程化落地与YOLOv8/v9实战】【C#工业上位机高级应用:高并发通信+性能优化】 【Java生产级避坑指南:

By Ne0inhk
ARM Linux 驱动开发篇--- Linux 并发与竞争实验(互斥体实现 LED 设备互斥访问)--- Ubuntu20.04互斥体实验

ARM Linux 驱动开发篇--- Linux 并发与竞争实验(互斥体实现 LED 设备互斥访问)--- Ubuntu20.04互斥体实验

🎬 渡水无言:个人主页渡水无言 ❄专栏传送门: 《linux专栏》《嵌入式linux驱动开发》《linux系统移植专栏》 ❄专栏传送门: 《freertos专栏》《STM32 HAL库专栏》 ⭐️流水不争先,争的是滔滔不绝  📚博主简介:第二十届中国研究生电子设计竞赛全国二等奖 |国家奖学金 | 省级三好学生 | 省级优秀毕业生获得者 | ZEEKLOG新星杯TOP18 | 半导纵横专栏博主 | 211在读研究生 在这里主要分享自己学习的linux嵌入式领域知识;有分享错误或者不足的地方欢迎大佬指导,也欢迎各位大佬互相三连 目录 前言  一、实验基础说明 1.1、互斥体简介 1.2 本次实验设计思路 二、硬件原理分析(看过之前博客的可以忽略) 三、实验程序编写 3.1 互斥体 LED 驱动代码(mutex.c) 3.2.1、设备结构体定义(28-39

By Ne0inhk
Flutter for OpenHarmony:swagger_dart_code_generator 接口代码自动化生成的救星(OpenAPI/Swagger) 深度解析与鸿蒙适配指南

Flutter for OpenHarmony:swagger_dart_code_generator 接口代码自动化生成的救星(OpenAPI/Swagger) 深度解析与鸿蒙适配指南

欢迎加入开源鸿蒙跨平台社区:https://openharmonycrossplatform.ZEEKLOG.net 前言 后端工程师扔给你一个 Swagger (OpenAPI) 文档地址,你会怎么做? 1. 对着文档,手写 Dart Model 类(容易写错字段类型)。 2. 手写 Retrofit/Dio 的 API 接口定义(容易拼错 URL)。 3. 当后端修改了字段名,你对着报错修半天。 这是重复劳动的地狱。 swagger_dart_code_generator 可以将 Swagger (JSON/YAML) 文件直接转换为高质量的 Dart 代码,包括: * Model 类:支持 json_serializable,带 fromJson/

By Ne0inhk
Linux 开发别再卡壳!makefile/git/gdb 全流程实操 + 作业解析,新手看完直接用----《Hello Linux!》(5)

Linux 开发别再卡壳!makefile/git/gdb 全流程实操 + 作业解析,新手看完直接用----《Hello Linux!》(5)

文章目录 * 前言 * make/makefile * 文件的三个时间 * Linux第一个小程序-进度条 * 回车和换行 * 缓冲区 * 程序的代码展示 * git指令 * 关于gitee * Linux调试器-gdb使用 * 作业部分 前言 做 Linux 开发时,你是不是也遇到过这些 “卡脖子” 时刻?写 makefile 时,明明语法没错却报错,最后发现是依赖方法行没加 Tab;想提交代码到 gitee,记不清 git add/commit/push 的 “三板斧”,还得反复搜教程;用 gdb 调试程序,输了命令没反应,才想起编译时没加-g生成 debug 版本;甚至连写个进度条,都搞不懂\r和\n的区别,导致进度条乱跳…… 其实这些问题,

By Ne0inhk