【代码随想录】算法训练营 第三天 第二章 链表 Part 1

news2025/1/12 3:56:31

目录

链表基础

 链表的定义

203. 移除链表元素

题目

思路

代码

直接删除法

虚拟头结点辅助法

707. 设计链表

题目

思路

代码

206. 反转链表

题目

思路

代码

双指针法

递归法


链表基础

链表是一种通过指针串在一起的线性结构,每个节点都由数据域和指针域组成,数据域存放节点数据,指针域存放指向下一个节点的指针,最后一个节点的指针指向null,也即这个指针为空指针。

 链表的定义

随想录中,标准的单链表定义如下:

struct ListNode {
	int val; // 数据域里的数据 
	ListNode *next; // 指针域里指向下个节点的指针 
	ListNode(int x) : val(x), next(NULL) {} // 构造函数,直接定义并初始化一个节点的数据域值为x 
};

ListNode* head = new ListNode(5); // 通过自己定义的构造函数来初始化节点,直接赋值为5 

ListNode* head = new ListNode(); 
head->val = 5; // 使用默认的构造函数来初始化节点,但是这里需要自己赋值 

203. 移除链表元素

题目

思路

力扣里已经定义好了链表,所以我们只需要使用ListNode* 来定义指针即可。

这道题需要我们删除和目标值相同的节点,所以我们的思路简单粗暴,一个一个比下去然后遇到就删除就是了,但是这里有一个问题,就是我们要如何删除一个节点呢,其实很简单,要删除一个节点分三步,第一步,定义一个指针指向该节点,第二步,将原本指向该节点的指针指向这个节点的下一个节点,第三步,删除我们新定义的这个指针(同时把指针指向的节点也删了)。

我们的代码有两种做法,一种是直接开干,将要删的节点分为头结点和中间节点,头结点先删,中间节点再用一个while语句来删;另一种是设置一个虚拟头结点,这样就不存在需要删除头结点的情况了,只需要删除中间节点即可,但是最后要注意,返回的是我们定义的虚拟头结点的下一个节点指针。

代码

直接删除法
/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode() : val(0), next(nullptr) {}
 *     ListNode(int x) : val(x), next(nullptr) {}
 *     ListNode(int x, ListNode *next) : val(x), next(next) {}
 * };
 */
class Solution {
public:
    ListNode* removeElements(ListNode* head, int val) {
        while (head != NULL && head->val == val) {
            ListNode* tmp = head;
            head = head->next;
            delete tmp;
        }
        ListNode* cur = head;
        while (cur != NULL && cur->next != NULL) {
            if (cur->next->val == val) {
                ListNode* tmp = cur->next;
                cur->next = cur->next->next;
                delete tmp;
            }
            else {
                cur = cur->next;
            }
        }
        return head;
    }
};
虚拟头结点辅助法
class Solution {
public:
    ListNode* removeElements(ListNode* head, int val) {
        ListNode* dummy = new ListNode(0);
        dummy->next = head;
        ListNode* cur = dummy;
        while (cur->next != NULL) {
            if(cur->next->val == val) {
                ListNode* tmp = cur->next;
                cur->next = cur->next->next;
                delete tmp;
            }
            else {
                cur = cur->next;
            }
        }
        head = dummy->next;
        return head;
    }
};

707. 设计链表

题目

设计一个链表,实现以下功能:

  • 获取元素;
  • 表头添加元素;
  • 表尾添加元素;
  • 表中添加元素;
  • 删除元素。

思路

这就是最简单的手搓链表了(bushi),在这里我们可以像上面那样给链表的前面添加一个虚拟头结点dummy,这样就不用考虑对头结点的特殊情况了,所有节点都一视同仁。

这就没什么思路不思路的了,思想很简单,实现是关键,真正写出来并且一点错没有,那就可以了,具体实现就看下面的代码吧。

注意,当你要开始复习链表的时候,就照着这个代码多抄多背,以后面试再也不用担心!

代码

class MyLinkedList {
public:
    // 定义链表节点结构体
    struct LinkedNode {
        int val;
        LinkedNode* next;
        LinkedNode(int val) : val(val), next(nullptr){}
    };
    
    // 初始化链表
    MyLinkedList() {
        dummy = new LinkedNode(0); // 定义一个虚拟头结点
        size = 0; // 链表的初始长度为0
    }

    // 获取第index个节点数值,如果index非法则直接返回-1,index从0开始
    int get(int index) {
        if (index < 0 || index > size - 1) {
            return -1;
        }
        LinkedNode* cur = dummy->next;
        while (index--) { // index可以看作数组下标,cur是从下标为0的节点开始的,所以这里循环index次没错
            cur = cur->next;
        }
        return cur->val;
    }
    
    // 在链表前面插入一个节点,插入完后新的节点称为链表的新头结点
    void addAtHead(int val) {
        LinkedNode* newNode = new LinkedNode(val);
        newNode->next = dummy->next;
        dummy->next = newNode;
        size++;
    }
    
    // 在链表最后添加一个节点
    void addAtTail(int val) {
        LinkedNode* newNode = new LinkedNode(val);
        LinkedNode* cur = dummy;
        while (cur->next != nullptr) {
            cur = cur->next;
        }
        cur->next = newNode;
        size++;
    }
    
    // 在链表中第index个节点前插入新节点
    void addAtIndex(int index, int val) {
        if (index > size) return;
        if (index < 0) index = 0;
        LinkedNode* newNode = new LinkedNode(val);
        LinkedNode* cur = dummy;
        while (index--) {
            cur = cur->next;
        }
        newNode->next = cur->next;
        cur->next = newNode;
        size++;
    }
    
    // 删除第index个节点
    void deleteAtIndex(int index) {
        if (index > size - 1 || index < 0) {
            return;
        }
        LinkedNode* cur = dummy;
        while (index--) {
            cur = cur->next;
        }
        LinkedNode* tmp = cur->next;
        cur->next = cur->next->next;
        delete tmp;
        tmp = nullptr;
        size--;
    }

    // 打印链表
    void print() {
        LinkedNode* cur = dummy;
        while (cur->next != nullptr) {
            cout << cur->next->val << " ";
            cur = cur->next;
        }
        cout << endl;
    }
private:
    int size;
    LinkedNode* dummy;
};

206. 反转链表

题目

思路

反转链表,就是从一个链表的第一个有效节点开始,逐一移出原链表,放到新链表的开头,

这样虽然原链表是从前往后拿走节点,但是新链表是从后往前一个一个加进去,这就完成了反转。

代码

双指针法
class Solution {
public:
    ListNode* reverseList(ListNode* head) {
        ListNode* temp; // 保存cur的下一个节点
        ListNode* cur = head; // 指向头结点
        ListNode* pre = NULL; // 新链表的头指针
        while (cur) { // 当原链表中还存在节点时
            temp = cur->next; // 保存cur的下一个节点,因为接下来要改变cur->next
            cur->next = pre; // 此时cur这个节点的下一个是新链表的第一个节点
            pre = cur; // 然后pre指针指向现在cur的这个结点
            cur = temp; // cur指向原链表的下一个结点
        }
        return pre;
    }
};
递归法
class Solution {
public:
    ListNode* reverse(ListNode* pre,ListNode* cur){
        if(cur == NULL) return pre;
        ListNode* temp = cur->next;
        cur->next = pre;
        // 可以和双指针法的代码进行对比,如下递归的写法,其实就是做了这两步
        // pre = cur;
        // cur = temp;
        return reverse(cur,temp);
    }
    ListNode* reverseList(ListNode* head) {
        // 和双指针法初始化是一样的逻辑
        // ListNode* cur = head;
        // ListNode* pre = NULL;
        return reverse(NULL, head);
    }

};

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

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

相关文章

初阶数据结构-常见的排序算法

排序 排序的概念常见的排序算法常见排序算法的实现数组的打印 插入排序直接插入排序的实现希尔排序( 缩小增量排序 )希尔排序的实现 交换排序冒泡排序冒泡排序的实现选择排序选择排序的实现堆排序堆排序的实现快速排序快速排序非递归 归并排序归并排序的递归实现归并排序的非递…

黑马JVM总结(三十五)

&#xff08;1&#xff09;JMM-有序性-问题 &#xff08;2&#xff09;JMM-有序性-解决 使用maven重新编译&#xff1a; 生成两个jar包 运行这个jar包&#xff1a; 再次执行上述结果&#xff1a;0出现的次数为0了 &#xff08;3&#xff09;JMM-有序性-理解 &#xff08;4&am…

2023_Spark_实验十六:编写LoggerLevel方法及getLocalSparkSession方法

一、搭建Spark项目结构 在SparkProject模块的pom.xml文件中增加一下依赖&#xff0c;并等待依赖包下载完毕&#xff0c;如上图。 ​<!-- Spark及Scala的版本号 --><properties><scala.version>2.11</scala.version><spark.version>2.1.1</sp…

组合数的计算

C: 即从a个元素中选取b个元素的组合数。 LL C(int a, int b) {LL res 1;for (int i a, j 1; j < b; i --, j )res res * i / j;return res; } A: 表示从a个元素中选取b个元素进行排列的情况数。 LL P(int a, int b) {LL res 1;for (int i a; i > a - b; i--){res…

2-k8s-控制器介绍

文章目录 一、控制器类型二、Deployment控制器三、SatefulSet控制器四、Daemonset控制器五、Job控制器六、CronJob 控制器 一、控制器类型 Deployment&#xff1a;适合无状态的服务部署StatefullSet&#xff1a;适合有状态的服务部署DaemonSet&#xff1a;一次部署&#xff0c…

iMazing 3中文版功能介绍免费下载安装教程

iMazing 3中文版免费下载是一款兼容Win和Mac的iOS设备管理软件。iMazing 3能够将音乐、文件、消息和应用等数据从任何 iPhone、iPad 或 iPod 传输到 Mac 或 PC 上。 使用iMazing 3独特的 iOS 备份功能保证数据安全:设定自动无线备份时间并支持快照;将备份保存到外接驱动器和网…

数据结构复盘——第四章:数组和矩阵

文章目录 第一部分:矩阵第一部分习题第二部分:对称矩阵第二部分习题第三部分:三角矩阵第三部分习题第四部分:三对角矩阵第四部分习题第五部分:稀疏矩阵第五部分习题小结第一部分:矩阵 矩阵在线性代数中已经有过详细了解,在考研中矩阵部分常常考察数组下标 k 与 矩阵行 …

5-k8s-探针介绍

文章目录 一、探针介绍二、探针类型三、探针定义方式四、探针实例五、启动探针测试六、存活探针测试七、就绪探针测试 一、探针介绍 概念 在 Kubernetes 中 Pod 是最小的计算单元&#xff0c;而一个 Pod 又由多个容器组成&#xff0c;相当于每个容器就是一个应用&#xff0c;应…

采用Spring Boot框架开发的医院预约挂号系统3e3g0+vue+java

本医院预约挂号系统有管理员&#xff0c;医生和用户。管理员功能有个人中心&#xff0c;用户管理&#xff0c;医生管理&#xff0c;科室信息管理&#xff0c;预约挂号管理&#xff0c;用户投诉管理&#xff0c;投诉处理管理&#xff0c;通知公告管理&#xff0c;科室分类管理。…

LeetCode24.两两交换链表中的节点

这道题还是比较简单&#xff0c;我看完题目的想法就是借助一个第三变量&#xff0c;来改变两个节点的指针的指向&#xff0c;比如我要改变1和2节点的指向&#xff0c;我用h1表示节点1&#xff0c;我创建一个新的节点ans&#xff0c;先拿ans指向节点2&#xff08;ans.next h1.n…

Linux性能优化--性能工具:网络

7.0 概述 本章介绍一些在Linux上可用的网络性能工具。我们主要关注分析单个设备/系统网络流量的工具&#xff0c;而非全网管理工具。虽然在完全隔离的情况下评估网络性能通常是无意义的(节点不会与自己通信),但是&#xff0c;调查单个系统在网络上的行为对确定本地配置和应用程…

从零开始的LINUX(二)

1.alias: 用法&#xff1a;取别名&#xff0c;此时code1是code的别名&#xff0c;对code1进行操作和对code进行操作结果一致。 如果原本文件名不存在&#xff0c;仍可以正常运行指令&#xff0c;不会报错。 2.stat 显示指定文件或目录的状态、属性。 3.touch 当文件名不存在的…

基于SSM+Vue的日用品网站设计与实现

末尾获取源码 开发语言&#xff1a;Java Java开发工具&#xff1a;JDK1.8 后端框架&#xff1a;SSM 前端&#xff1a;Vue 数据库&#xff1a;MySQL5.7和Navicat管理工具结合 服务器&#xff1a;Tomcat8.5 开发软件&#xff1a;IDEA / Eclipse 是否Maven项目&#xff1a;是 目录…

数据结构复盘——第一章:绪论

文章目录 第一部分:数据的专业术语1、数据2、数据元素3、数据项4、数据对象5、数据类型6、抽象数据类型(ADT)第一部分习题第二部分:数据结构1、逻辑结构:2、存储结构(又称物理结构)︰3、运算:第二部分习题第三部分:算法1、算法的五个特性2、算法的设计五个要求第三部分习题…

antd的RangePicker设置默认值,默认近七天(andt+react)

import moment from "moment";state {initData:[moment().startOf(day).subtract(6, d), moment().endOf(day)], }<FormItem label"产生时间" {...tailItemLayout}>{getFieldDecorator("produceTime", {initialValue: initData})(<Ran…

C语言 形参、实参

定义 形参 形式上的参数&#xff0c;没有确定的值 实参 实际存在的&#xff0c;已经确定的参数&#xff0c;常量&#xff0c;变量&#xff0c;表达式&#xff0c;都是实参 区别 实参的值不随形参的变化而变化 在C语言中&#xff0c;数据传送是单向的&#xff0c;即只能把实…

【软考】14.2 统一建模语言UML/事务关系图

《统一建模语言UML》 可视化的建模语言&#xff0c;非程序设计语言UML的结构&#xff1a;构造块&#xff08;事物、关系、图&#xff09;、规则、公共机制 模型的事物 结构事物&#xff1a;静态行为事物&#xff1a;动态分组事物&#xff1a;组织注释事物&#xff1a;解释 事…

基于寄生捕食优化的BP神经网络(分类应用) - 附代码

基于寄生捕食优化的BP神经网络&#xff08;分类应用&#xff09; - 附代码 文章目录 基于寄生捕食优化的BP神经网络&#xff08;分类应用&#xff09; - 附代码1.鸢尾花iris数据介绍2.数据集整理3.寄生捕食优化BP神经网络3.1 BP神经网络参数设置3.2 寄生捕食算法应用 4.测试结果…

GPT绘制流程图咒语

【咒语】下面是我的一篇论文选取部分&#xff0c;为了让读者更好理解&#xff0c;我准备画一张图&#xff0c;请你阅读后为我设计一下这个图应该怎么画&#xff0c;更有说服力&#xff0c;更容易理解 论文片段&#xff1a; 多模态数据融合研究的基础在于有效的数据采集。首先&a…

DIY私人图床:使用CFimagehost源码自建无需数据库支持的PHP图片托管服务

文章目录 1.前言2. CFImagehost网站搭建2.1 CFImagehost下载和安装2.2 CFImagehost网页测试2.3 cpolar的安装和注册 3.本地网页发布3.1 Cpolar临时数据隧道3.2 Cpolar稳定隧道&#xff08;云端设置&#xff09;3.3.Cpolar稳定隧道&#xff08;本地设置&#xff09; 4.公网访问测…