代码随想录day3 | 203.移除链表元素 707.设计链表 206.反转链表

news2024/12/23 5:07:03

文章目录

    • 一、移除链表元素的思想
      • 两种方法
    • 二、203.移除链表元素
    • 三、707.设计链表
    • 四、206.反转链表

一、移除链表元素的思想

直接让前一个节点指向后一个节点即可

两种方法

第一种:直接删除
第二种:头删的时候,直接head=head->next

其实这两种方法都没有做到统一

第三种:虚拟头结点法
这样的话,咱们删除的时候,就是以统一的规则来进行删除啦!
在这里插入图片描述

二、203.移除链表元素

203.移除链表元素
法一:原始删除法

class Solution
{
public:
    ListNode *removeElements(ListNode *head, int val)
    {
        // 头删
        while (head != nullptr && head->val == val)
        {
            ListNode *tmp = head;
            head = head->next;
            delete tmp;
        }
        // 接下来不是头删,正常的中间删除
        ListNode *cur = head;
        while (cur != nullptr && cur->next != nullptr)
        {
            if (cur->next->val == val)
            {
                ListNode *tmp = cur->next;
                cur->next = cur->next->next;
                delete tmp; // 内存释放
            }
            else
            {
                cur = cur->next;
            }
        }
        return head;
    }
};

1、while(head!=nullptr && head->val == val)?

注意使用while 而不是 if ,因为会有特殊情况,持续删除头结点的情况,所以使用外while。

2、if(cur->next->val==val)

我们是使用的cur的next的值来判断是不是我们想要删除的val的。如果我们直接使用cur的值来判断的话,我们是不好来找到当前节点的上一个节点,从而链接起来的。

法二:虚拟头结点法

在这里插入图片描述

class Solution
{
public:
    ListNode *removeElements(ListNode *head, int val)
    {
        // 虚拟头结点来删除
        ListNode *dummy = new ListNode(-1);
        dummy->next = head;
        ListNode *cur = dummy; // 为啥从dummy起始?
        while (cur->next != nullptr)
        {
            if (cur->next->val == val)// 为啥用cur->next->val 作为判断?
            {
                cur->next = cur->next->next;
            }
            else
            {
                cur = cur->next;
            }
        }
        return dummy->next;
    }
};

1、ListNode *cur = dummy; // cur为啥从dummy起始?

而不是cur=head?
我们删除链表元素一定要知道上一个元素的指针是啥,我们删的是cur->next->val。

2、while (cur->next != nullptr)

遍历的时候,我们要判断的是cur->next->val,所以我们while (cur->next != nullptr) 要这么写。

3、if (cur->next->val == val)// 为啥用cur->next->val 作为判断?

我们是使用的cur的next的值来判断是不是我们想要删除的val的。如果我们直接使用cur的值来判断的话,我们是不好来找到当前节点的上一个节点,从而链接起来的。

4、为啥return dummy->next;

因为return head;有可能head已经被删除了。

三、707.设计链表

707.设计链表

统一使用虚拟头结点的方式,让我们的操作统一化。
我们还需要一个虚拟头节点_dummy作为头节点,和一个_size参数保存有效节点数。注意题目下标从0开始。

一定要注意:我们的临时变量定义cur=_dummy,操作的是cur->next,这样我才能方便的增加、删除,这才是对应到我们的第index(或者说第n个节点)。

class MyLinkedList
{
public:
    // 定义链表节点结构体
    struct ListNode
    {
        int val;
        ListNode *next;
        ListNode(int val) : val(val), next(nullptr) {}
    };
    MyLinkedList()
    {
        // 定义虚拟头结点
        _dummy = new ListNode(-1);
        _size = 0;
    }


// 获取到第index个节点数值,如果index是非法数值直接返回-1, 注意index是从0开始的,第0个节点就是头结点
// 注意 index和_size差值为1
    int get(int index)
    {
        if (index > (_size - 1) || index < 0)
        {
            return -1;
        }
        ListNode *cur = _dummy->next; // 从头开始遍历寻找
        // 注意下标从0开始
        while (index)
        {
            cur = cur->next;
            index--;
        }
        return cur->val;
    }

    void addAtHead(int val)
    {
        ListNode *newnode = new ListNode(val);

        // 这两步顺序不能交换
        newnode->next = _dummy->next;
        _dummy->next = newnode;

        _size++;
    }

    void addAtTail(int val)
    {
        ListNode *newnode = new ListNode(val);
        // 找尾
        ListNode *cur = _dummy; // 为啥从dummy开始?
        while (cur->next != nullptr)
        {
            cur = cur->next;
        }
        cur->next = newnode;
        _size++;
    }

	
	// 如果index大于链表的长度,则返回空
    // 如果index小于0,则在头部插入节点
    void addAtIndex(int index, int val)
    {
        if (index > _size)
            return;
        if (index < 0)
            index = 0;
            
        // 一定要找到第index个节点的前驱
        ListNode *newnode = new ListNode(val);
        ListNode *cur = _dummy;
        // 遍历找到第n个节点
        while (index--)
        {
            cur = cur->next;
        }
        // 这下面两步顺序也是不能换的
        newnode->next = cur->next;
        cur->next = newnode;
        _size++;
    }

    void deleteAtIndex(int index)
    {
        if (index < 0 || index >= _size)
        {
            return;
        }
        ListNode *cur = _dummy;
        // 遍历找到第n个节点
        while (index--) // 当index=0时,while循环就不会执行了
        {
            cur = cur->next;
        }
        ListNode *tmp = cur->next;
        cur->next = cur->next->next;
        delete tmp;
        tmp = nullptr;
        _size--;
    }

private:
    int _size;
    ListNode *_dummy;
};

1、头插顺序不能变

在这里插入图片描述

2、addAtTail 中ListNode * cur=_dummy;// 为啥从dummy开始?

因为有可能刚刚开始没有元素,相当于在dummy后插入。

3、注意index与size之间的关系,他们差值为1

四、206.反转链表

206.反转链表
面试中经常出现

双指针法

// 双指针
class Solution
{
public:
    ListNode *reverseList(ListNode *head)
    {
        ListNode *cur = head;
        ListNode *pre = nullptr;
        while (cur != nullptr)
        {
            ListNode *tmp = cur->next;
            cur->next = pre; // 反转操作
            // 下面两步不能换顺序
            pre = cur;
            cur = tmp;
        }
        return pre;
    }
};

1、为啥要这样初始化?

因为这样初始化,直接让咱们的反转后的尾节点直接执行nullptr了。
在这里插入图片描述

2、while( ? ) 循环结束调条件是啥

就是cur为空就结束了,最后一步,不再需要nullptr指向pre了,没有意义。while(cur)就行了。

3、为啥需要每次进入循环都要定义一个tmp临时变量?

因为这样可以方便更新cur,反转后,cur无法后移指向下一个节点,tmp保存cur->next,趁着pre和cur还连着的时候先保存下来,然后就可以赋值了,一定要先移pre,后移动cur。
在这里插入图片描述

递归法

class Solution
{
public:
    // 子函数
    ListNode *reverse(ListNode *cur, ListNode *pre)
    {
        if (cur == nullptr)
            return pre;           // 2.终止条件就是cur指向nullptr
        ListNode *tmp = cur->next;
        cur->next = pre;          // 3.反转操作
        return reverse(tmp, cur); // 4、进入下一层循环(递归) 谁赋值给cur? 谁赋值给pre?
    }

    ListNode *reverseList(ListNode *head)
    {
        return reverse(head, nullptr); // 1.head赋值给cur,nullptr赋值给pre
    }
};

从后往前翻转指针指向 递归

  • 使用递归函数,一直递归到链表的最后一个结点,该结点就是反转后的头结点,记作last
  • 此后,每次函数在返回的过程中,让当前结点的下一个结点的next指针指向当前节点。
  • 同时让当前结点的neat指针指向NULL,从而实现从链表尾部开始的局部反转
  • 当递归函数全部出栈后,链表反转完成。
class Solution {
public:
    ListNode* reverseList(ListNode* head) {
        // 边缘条件判断
        if(head == NULL) return NULL;
        if (head->next == NULL) return head;
        
        // 递归调用,翻转第二个节点开始往后的链表
        ListNode *last = reverseList(head->next);
        // 翻转头节点与第二个节点的指向
        head->next->next = head;
        // 此时的 head 节点为尾节点,next 需要指向 NULL
        head->next = NULL;
        return last;
    }
}; 

在这里插入图片描述

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

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

相关文章

JAVA数据结构、集合操作及常用API_C++开发转JAVA

文章目录 零、引言一、JAVA数据结构基础1.0 数据类型概述1.1 基本数据类型 零、引言一、JAVA数据结构基础1.0 数据类型概述1.1 基本数据类型1.2 包装类1.3 基本类型和包装类型的区别1.4 包装类型的缓存机制1.5 equals() 和 1.6 自动装箱拆箱1.7 浮点数精度丢失1.8 数值、字符转…

windows下配置pytorch + yolov8+vscode,并自定义数据进行训练、摄像头实时预测

最近由于工程需要&#xff0c;研究学习了一下windows下如何配置pytorch和yolov8&#xff0c;并自己搜集数据进行训练和预测&#xff0c;预测使用usb摄像头进行实时预测。在此记录一下全过程 一、软件安装和配置 1. vscode安装 windows平台开发python&#xff0c;我采用vscod…

Python基础合集 练习26 (turtle库的使用)

turtle是标准库 import turtle as t 窗口最小单位为像素 t.steup(width,height,起始点,起始点) 不是必须的 t.setup(800, 400) 不设置后面的起始点默认在中间 空间坐标体系 绝对坐标 四个象限 t.goto(x,y) 让某个位置的海龟到达某个地方 t.goto(100,100) t.goto(10…

使用flask开启一个简单的应用

Flask是非常流行的 Python Web框架&#xff0c;它能如此流行&#xff0c;原因主要有如下几点: 。有非常齐全的官方文档,上手非常方便。 。有非常好的扩展机制和第三方扩展环境&#xff0c;.工作中常见的软件都会有对应的扩展。自己动手实现扩展也很容易。 。社区活跃度非常高。…

【可解释学习】PyG可解释学习模块torch_geometric.explain

PyG可解释学习模块torch_geometric.explain PhiloshopyExplainerExplanationsExplainer AlgorithmExplanation Metrics参考资料 torch_geometric.explain是PyTorch Geometric库中的一个模块&#xff0c;用于解释和可视化图神经网络&#xff08;GNN&#xff09;模型的预测结果。…

RestClient操作文档和DSL查询语法

一、 文档操作 1、新增文档 本案例中&#xff0c;hotel为索引库名&#xff0c;61083为文档idTestvoid testAddDocument() throws IOException {// 1.根据id查询酒店数据Hotel hotel hotelService.getById(61083L);// 2.转换为文档类型HotelDoc hotelDoc new HotelDoc(hotel…

【数据结构】二叉树——链式结构

目录 一、前置声明 二、二叉树的遍历 2.1 前序、中序以及后序遍历 2.2 层序遍历 三、节点个数以及高度 3.1 节点个数 3.2 叶子节点个数 3.3 第k层节点个数 3.4 二叉树的高度/深度 3.5 查找值为x的节点 四、二叉树的创建和销毁 4.1 构建二叉树 4.2 二叉树销毁 4.3 …

2023年7月14日,ArrayList底层

集合框架图&#xff1a; 集合和数组的区别 AarrayList ArrayList底层实现原理 ArrayList的底层实现是基于数组的动态扩容。 初始容量&#xff1a;当创建一个新的ArrayList对象时&#xff0c;它会分配一个初始容量为10的数组。这个初始容量可以根据需求进行调整。 //表示默认的…

在Python中优雅地用多进程:进程池 Pool、管道通信 Pipe、队列通信 Queue、共享内存 Manager Value

Python 自带的多进程库 multiprocessing 可实现多进程。我想用这些短例子示范如何优雅地用多线程。中文网络上&#xff0c;有些人只是翻译了旧版的 Python 官网的多进程文档。而我这篇文章会额外讲一讲下方加粗部分的内容。 创建进程 Process&#xff0c;fork 直接继承资源&am…

zigbee DL-20无线串口收发模块使用(双车通讯,电赛模块推荐)

前言 &#xff08;1&#xff09;通常有时候&#xff0c;我们可能会需要让两个MCU进行通讯。而zigbee是最适合两个MCU短距离通讯的模块。他使用极其简单&#xff0c;非常适合两款MCU之间的进行数据交互。 &#xff08;2&#xff09;在各类比赛中&#xff0c;经常出现需要两个MCU…

独立看门狗 IWDG

独立看门狗介绍 Q&#xff1a;什么是看门狗&#xff1f; A&#xff1a;可以理解为对于一只修勾的定时投喂&#xff0c;如果不给它吃东西就会狂叫&#xff0c;因此可以通过观察修勾的状态来判断喂它的人有没有正常工作。 在由单片机构成的微型计算机系统中&#xff0c;由于单…

【业务功能篇44】Mysql 海量数据查询优化,进行分区操作

业务场景&#xff1a;当前有个发料表&#xff0c;随着业务数据量增多&#xff0c;达到了几千万级别水平&#xff0c;查询的效率就越来越低了&#xff0c;针对当前的架构情况&#xff0c;我们进行了分区的设置&#xff0c;通过对时间字段&#xff0c;按年月&#xff0c;一个月作…

ios 启动页storyboard 使用记录

本文简单记录ios启动页storyboard 如何使用和注意事项。 xcode窗口简介 以xcode14为例&#xff0c;新建项目如下图&#xff0c;左边文件栏中的LaunchScreen.storyboard 为默认启动页布局。窗口中间部分是storyboard中的组件列表&#xff0c;右侧为预览&#xff0c;可以看到渲…

H3C-Cloud Lab-实验-DHCP实验

实验拓扑图&#xff1a; 实验需求&#xff1a; 1、按照图示为R1配置IP地址 2、配置R1为DHCP服务器&#xff0c;提供服务的地址池为192.168.1.0/24网段&#xff0c;网关为192.168.1.254&#xff0c;DNS服务器地址为202.103.24.68&#xff0c;202.103.0.117 3、192.168.1.10-1…

Camtasia Studio 2023 最新中文版,camtasiaStudio如何添加背景音乐

Camtasia2023的视频编辑工具可以帮助用户剪辑、裁剪、旋转、调整大小、添加特效、混合音频等。用户还可以使用Camtasia2023的字幕功能添加字幕和注释&#xff0c;以及使用其内置的特效和转场来提高视频的视觉效果。 Camtasia Studio 2023新功能介绍 的光标增强 由于光标在屏幕…

解决win10电脑无法访问局域网内其它共享文件问题

问题描述 今天需要上传文件到一个共享的局域网文件夹里&#xff0c;在我的电脑和浏览器访问//192.168.0.16//public都提升访问受限&#xff0c;开始以为是因为用户没授权&#xff0c;后来一般沟通后&#xff0c;发现其它电脑都能正常访问的&#xff0c;所以确定是自己电脑配置…

Caerulein,17650-98-5,雨蛙肽,以三氟醋酸盐形式提供的十肽分子

资料编辑|陕西新研博美生物科技有限公司小编MISSwu​ Caerulein |雨蛙素&#xff0c;雨蛙肽&#xff0c;蓝肽| CAS&#xff1a;17650-98-5 | 纯度&#xff1a;95% ------雨蛙素结构式---- ----试剂参数信息--- CAS号&#xff1a;17650-98-5 外观&#xff08;Appearance&a…

java中使用POI生成Excel并导出

注&#xff1a;本文章中代码均为本地Demo版本&#xff0c;若后续代码更新将不会更新文章 需求说明及实现方式 根据从数据库查询出的数据&#xff0c;将其写入excel表并导出 我的想法是通过在实体属性上写自定义注解的方式去完成。因为我们在代码中可以通过反射的方式去获取实体…

js小写金额转大写 自动转换

// 小写转为大写convertCurrency(money) {var cnNums [零, 壹, 贰, 叁, 肆, 伍, 陆, 柒, 捌, 玖]var cnIntRadice [, 拾, 佰, 仟]var cnIntUnits [, 万, 亿, 兆]var cnDecUnits [角, 分, 毫, 厘]// var cnInteger 整var cnIntLast 元var maxNum 999999999999999.9999var…

vulnhub靶场red:1教程

靶场搭建 靶机下载地址&#xff1a;Red: 1 ~ VulnHub 难度&#xff1a;中等 信息收集 arp-scan -l 这里没截图忘记了&#xff0c;就只是发现主机 扫描端口 nmap --min-rate 1000 -p- 192.168.21.130 nmap -sT -sV -sC -O -p22,80 192.168.21.130 先看80端口 看到链接点一…