代码随想录算法训练营第三天 | 203. 移除链表元素、 707. 设计链表、206.反转链表

news/2024/10/21 4:49:15

链表基础

链表分为单链表、双链表和循环链表,链表在内存中与数组不同,不是连续存储的。

C++中链表的定义方式如下:

// 单链表
struct ListNode {int val;  // 节点上存储的元素ListNode *next;  // 指向下一个节点的指针ListNode(int x) : val(x), next(NULL) {}  // 节点的构造函数
};

这里引用代码随想录卡哥总结的数组和链表的区别:

6-203.移除链表元素

给你一个链表的头节点head 和一个整数val ,请你删除链表中所有满足Node.val == val 的节点,并返回新的头节点

 

示例 1:

输入:head = [1,2,6,3,4,5,6], val = 6
输出:[1,2,3,4,5]

示例 2:

输入:head = [], val = 1
输出:[]

示例 3:

输入:head = [7,7,7,7], val = 7
输出:[]

 

提示:

  • 列表中的节点数目在范围 [0, 104] 内
  • 1 <= Node.val <= 50
  • 0 <= val <= 50

删除头节点和非头节点的操作是不一样的,这样会导致程序写起来较为复杂,首先给出一个使用不同操作来删除的代码:

class Solution {
public:ListNode* removeElements(ListNode* head, int val) {while(head != NULL && head->val == val){//删除头结点ListNode* tmp =  head;//这里要临时创建一个tmp以便于后续释放空间head = head -> next;delete tmp;//释放内存}ListNode* cur = head;while(cur != NULL && cur->next!= NULL){//删除非头结点if(cur->next->val == val){ListNode* tmp = cur->next;//临时创建一个tmp以便于后续释放空间cur->next = cur->next->next;delete tmp;//释放内存}else{cur = cur->next;}}return head;}
};

删除头节点,首先判断头节点是否为空,如果为空则直接返回,当头节点指向的值为target的时候,我们删除头节点,删除前记得创建一个临时指针便于后续释放空间。

然后就可以定义一个cur来指向目前的头节点,对后续节点进行操作了。

删除后续节点,依旧判断是否为空,为空则返回,不为空且下一节点不为空时,判断指向的值是否为target,是则删除当前节点,释放空间cur向后移动一位,不是则直接向后移动一位。最后返回head即可。

使用虚拟头节点

使用虚拟头节点的好处是,当我们使用后,就可以使用统一的判断逻辑来操作后续所有节点,无需像上述代码一样需要预先判断是否为头节点。使用虚拟头节点的代码如下所示:

class Solution {
public:ListNode* removeElements(ListNode* head, int val) {ListNode* dummyhead= new ListNode(0);dummyhead -> next = head;ListNode* cur = dummyhead;while(cur != NULL && cur->next!= NULL){//删除结点if(cur->next->val == val){ListNode* tmp = cur->next;//临时创建一个tmp以便于后续释放空间cur->next = cur->next->next;delete tmp;//释放内存}else{cur = cur->next;}}head = dummyhead->next;delete dummyhead;return head;}
};

在使用链表时,多画图可以帮助理解为什么有些地方指向next更好,有些地方则是直接指向目标。这里在最后返回时有一个需要注意的点,就是head可能已经被我们删除了,那么此时链表的头其实是dummyhead指向的下一个位置。

7-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

 

提示:

  • 0 <= index, val <= 1000
  • 请不要使用内置的 LinkedList 库。
  • 调用 getaddAtHeadaddAtTailaddAtIndex 和 deleteAtIndex 的次数不超过 2000 。

设计链表问题,要求对链表有较好的掌握,第一次看还是有点晕,以前完全没学过链表这个类型,遇到了相当的困难,不过还是跟着视频写下来了。这里就只贴代码了,二刷再复习思路。

class MyLinkedList {
public:struct LinkedNode {int val;LinkedNode* next;LinkedNode(int val):val(val), next(nullptr){}};MyLinkedList() {_dummyHead = new LinkedNode(0);_size = 0;}int get(int index) {if (index > (_size - 1) || index < 0) {return -1;}LinkedNode* cur = _dummyHead->next;while(index--){ // 如果--index 就会陷入死循环cur = cur->next;}return cur->val;}void addAtHead(int val) {LinkedNode* newNode = new LinkedNode(val);newNode->next = _dummyHead->next;_dummyHead->next = newNode;_size++;}// 在链表最后面添加一个节点void addAtTail(int val) {LinkedNode* newNode = new LinkedNode(val);LinkedNode* cur = _dummyHead;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;if(index < 0) index = 0;LinkedNode* newNode = new LinkedNode(val);LinkedNode* cur = _dummyHead;while(index--){cur = cur->next;}newNode->next = cur->next;cur->next = newNode;_size++;}void deleteAtIndex(int index) {if (index >= _size || index < 0) {return;}LinkedNode* cur = _dummyHead;while(index--){cur = cur->next;}LinkedNode* tmp = cur->next;cur->next = cur->next->next;delete tmp;tmp = nullptr;_size--;}private:int _size;LinkedNode* _dummyHead;
};

8-206.反转链表

这题目明天来补,到时候再编辑

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈,一经查实,立即删除!

相关文章

MySQL时区导致无法产生表

MySQL时区导致无法产生表 解决问题加上 &serverTimezone=UTC日志信息 2024-10-21 01:56:19.719 INFO 26556 --- [ main] com.li.BackEndApplication : Starting BackEndApplication on LIJIANTPC with PID 26556 (D:\project\blogs\back-end\tar…

我在大厂做 CR——如何体系化防控空指针异常

大家好,我是木宛哥,今天和大家分享下——代码 CR 时针对恼人的空指针异常(NullPointerException)如何做到体系化去防控; 什么是空指针异常 从内存角度看,对象的实例化需要在堆内存中分配空间。如果一个对象没有被创建,那也就没有分配内存,当应用程序访问空对象时,实际…

U4字符串以及正则表达式

Unit4字符串以及正则表达式方法 描述capitalize() 把首字符转换为大写。casefold() 把字符串转换为小写。center() 返回居中的字符串。count() 返回指定值在字符串中出现的次数。encode() 返回字符串的编码版本。endswith() 如果字符串以指定值结尾,则返回 true。expandtabs()…

内网渗透-内网信息收集

简单内网信息收集分享。目录Windows本地基础信息收集权限查看指定用户的详细信息查看防火墙状态机器基础信息查看系统信息查看进程情况软件安装情况查看计划任务网络环境查看网络配置信息查看网络连接情况查看是否存在域扫描网段WMIC收集信息抓本地密码LaZagne抓密码mimikatz 抓…

jenkins安装提示无法启动

想必大家会遇到以下问题: jenkins安装时因错误导致需要二次或者多次安装jenkins.msi,系统会提示sevice jenkinsfailed to start ,verify that you have sufficient privileges to start system services (服务jenkins启动失败,请确认你有足够的权限来启动系统服务) 解决…

《使用Gin框架构建分布式应用》阅读笔记:p101-p107

《用Gin框架构建分布式应用》学习第7天,p101-p107总结,总计7页。 一、技术总结 1.StatusBadRequest vs StatusInternalServerError 写代码的时候有一个问题,什么时候使用 StatusBadRequest(400错误),什么时候使用 StatusInternalServerError(500错误)? 400用于客户端侧的错…

学习web进程

目前html和css js基础了解 可以做一些效果页面 学到110节课就可以做用户注册页面了 加油加油