【算法练习Day3】 移除链表元素设计链表反转链表

news2024/11/20 4:33:51

在这里插入图片描述

​📝个人主页:@Sherry的成长之路
🏠学习社区:Sherry的成长之路(个人社区)
📖专栏链接:练题
🎯长路漫漫浩浩,万事皆有期待

文章目录

  • 移除链表元素
    • 其他问题
  • 设计链表
    • 其他问题
  • 反转链表
    • 其他问题
  • 总结:

移除链表元素

203. 移除链表元素 - 力扣(LeetCode)

链表问题大多都可以用虚拟头结点的方法,使链表的插入和删除操作变得简单。

class Solution {
public:
    ListNode* removeElements(ListNode* head, int val) {
        ListNode* dunnmyhead=new ListNode(0);// 设置一个虚拟头结点
        dunnmyhead->next=head;// 将虚拟头结点指向head,这样方面后面做删除操作
        ListNode* cur=dunnmyhead;
        while(cur->next!=nullptr)
        {
            if(cur->next->val==val)
            {
                ListNode* tmp=cur->next;
                cur->next=cur->next->next;
                delete tmp;
            }
            else
            {
                cur=cur->next;
            }
        }
        head=dunnmyhead->next;
        delete dunnmyhead;
        return head;
    }
};

这道题并不难,值得注意的是,创建一个临时指针,指向head,然后判断它的值是否等于val,要注意的是用cur->next->val来判断值是否是我们需要找的,如果是的话,cur指向的正是要删除节点的上一个节点,直接将cur的next指针连到要删除节点的下一个位置就可以了

其他问题

注意:指针问题, 写删除链表题的时候经常少了else判断, 链表首要想好指针是怎么移动的,是否会访问null即可

● 对于链表问题可以多用笔画画图,这样会加深对指针和节点实体的理解,代码的鲁棒性如何通常可以利用边界case尝试,很多都是因为空指针的错误,手动画图走一遍自己的代码一般就能发现。

● 是否要添加虚拟头结点 :
虚拟头结点的主要目的是为了避免对头结点的特殊处理;这个处理就指的是修改操作。所以可以这样:涉及到对链表修改(如插入,删除,移动)的,都加个dummy,只是遍历取点就可以不用加

设计链表

707. 设计链表 - 力扣(LeetCode)

设计链表是一道综合题,涵盖了很多有关于链表的函数接口,适合练习,整体思路不算很难。

class MyLinkedList {
public:
	// 定义链表节点结构体
    struct Listnode
    {
        int val;
        Listnode* next;
        Listnode(int val)
            :val(val)
            ,next(nullptr)
        {

        }
    };

	// 初始化链表
    MyLinkedList() {
        _size=0;
        _dummyHead=new Listnode(0);// 这里定义的头结点 是一个虚拟头结点,而不是真正的链表头结点

    }
    // 获取到第index个节点数值,如果index是非法数值直接返回-1, 注意index是从0开始的,第0个节点就是头结点
    int get(int index) {
        if(index<0||index>(_size-1))
        {
            return -1;
        }
        Listnode* cur=_dummyHead->next;
        while(index--) // 如果--index 就会陷入死循环
        {
            cur=cur->next;
        }
        return cur->val;

    }
     // 在链表最前面插入一个节点,插入完成后,新插入的节点为链表的新的头结点
    void addAtHead(int val) {
        Listnode* newnode=new Listnode(val);
        newnode->next=_dummyHead->next;
        _dummyHead->next=newnode;
        _size++;

    }
    // 在链表最后面添加一个节点
    void addAtTail(int val) {
        Listnode* newnode=new Listnode(val);
        Listnode*cur=_dummyHead;
        while(cur->next)
        {
            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;
        }
        Listnode* newnode=new Listnode(val);
        Listnode* cur=_dummyHead;
        while(index--)
        {
            cur=cur->next;
        }
        newnode->next=cur->next;
        cur->next=newnode;
        _size++;

    }
     // 删除第index个节点,如果index 大于等于链表的长度,直接return,注意index是从0开始的
    void deleteAtIndex(int index) {
        if(index<0||index>(_size-1))
        {
            return ;
        }
        Listnode* cur=_dummyHead;
        while(index--)
        {
            cur=cur->next;
        }
        Listnode* tmp=cur->next;
        cur->next=cur->next->next;
        delete tmp;
         //delete命令指示释放了tmp指针原本所指的那部分内存,
        //被delete后的指针tmp的值(地址)并非就是NULL,而是随机值。也就是被delete后,
        //如果不再加上一句tmp=nullptr,tmp会成为乱指的野指针
        //如果之后的程序不小心使用了tmp,会指向难以预想的内存空间
        tmp=nullptr;
        _size--;        
    }

private:
    int _size;
    Listnode* _dummyHead;
};

起初写的时候很懵,还在想为什么没有给头节点指针,而是只有index?后来看题解才知道要自己创建结构体,和虚拟头节点(方便空链表插入)。整体思路难度适中,只是接口多了一些,思路清晰还是能写出得出来的。

其他问题

● 设计链表因为调用了很多函数,一旦出错可能不知道调试从何下手,因此建议把代码放到本地IDE上,一个一个函数去测试看出错在什么地方

● 对于第index个有所混淆,做题目前一定要理解题目的意思,这里的index是从0开始的

● addAtIndex 方法中描述的“如果 index 等于链表的长度,则该节点将附加到链表的末尾” 这句话中 链表长度这里是指 size而不是size - 1,如果是size-1的话那就会和在最后一个元素前插入冲突了

反转链表

206. 反转链表 - 力扣(LeetCode)

思路明确的同时还要注意head指针传进来时,若是空的情况要怎么处理,以及应该创建几个临时节点,分别保存什么。

class Solution {
public:
    ListNode* reverseList(ListNode* head) {
        ListNode* tmp=nullptr;// 保存cur的下一个节点
        ListNode* cur=head;
        ListNode* pre=nullptr;
        while(cur)
        {
            tmp=cur->next; // 保存一下 cur的下一个节点,因为接下来要改变cur->next
            cur->next=pre;// 翻转操作
            pre=cur; // 更新pre 和 cur指针
            cur=tmp;
        }
        return pre;
    }
};

注意:更新pre 和 cur指针时,先让pre=cur,否则,cur指向的节点就丢失了

创立三个临时指针,一个用来保存要反转的节点的下一个链接节点,一个用来指向下一个反转节点的next连接到哪里,另一个代表当前要反转的节点。缺一不可的,一开始pre要指向null,使第一个反转的链表有指向的指针,只要明确要用到几个指针,以及分别初始化为什么值,这道题就解的出来了。

递归代码实现,和上面的方法思路是相同的。

class Solution {
public:
    ListNode* reverse(ListNode* pre,ListNode* cur)
    {
        if(cur==nullptr)
        {
            return pre;
        }
        ListNode* tmp=cur->next;
        cur->next=pre;
        // 可以和双指针法的代码进行对比,如下递归的写法,其实就是做了这两步
        // pre = cur;
        // cur = temp;
        return reverse(cur,tmp);
    }
    ListNode* reverseList(ListNode* head) {
        // 和双指针法初始化是一样的逻辑
        // ListNode* cur = head;
        // ListNode* pre = NULL;
       return reverse(nullptr,head);
    }
};

其他问题

● 链表一定要分清节点和指针的概念。 new ListNode()是真实存在的一个节点, head = new ListNode() 相当于 head指针指向了一个真实的节点, node = head, 相当于node和head同时指向了这个真实的节点

● 尽量不要去动虚拟头节点,因为虚拟头节点本来就是个工具节点,操作后面的节点本身就好

● 为什么有时候需要判定cur->next !=nullptr 有时候又不需要 只用判断cur!=nullptr呢?
其实这个要看场景,一般就是看你如果不判断的话会不会导致空指针异常,因为如果你的指针遍历到null还调用它的属性或方法肯定就会报错的,但是有时候的情况不会遍历到cur->next,所以要看具体情况。

总结:

今天的三道题虽然之前做过,但从循环到递归的转变感觉第一次非常清晰的领悟了。接下来,我们继续进行算法练习·。希望我的文章和讲解能对大家的学习提供一些帮助。

当然,本文仍有许多不足之处,欢迎各位小伙伴们随时私信交流、批评指正!我们下期见~

在这里插入图片描述

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

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

相关文章

【LeetCode热题100】--53.最大子数组和

53.最大子数组和 使用动态规划&#xff1a; 状态定义&#xff1a;设动态规划列表dp&#xff0c;dp[i]代表以元素nums[i]为结尾的连续子数组最大和 转移方程&#xff1a;若dp[i-1]≤0,说明dp[i-1]对dp[i]产生负贡献&#xff0c;即dp[i-1]nums[i]还不如nums[i]本身大 初始状态&…

基于Python+Pygame实现一个俄罗斯方块小游戏【完整代码】

俄罗斯方块&#xff0c;一款起源于上世纪80年代的经典电子游戏&#xff0c;凭借简单的规则和独特的魅力&#xff0c;一跃成为全球家喻户晓的经典。你知道其实只需要一些基础的编程知识&#xff0c;就可以自己实现它吗&#xff1f;今天&#xff0c;我们将使用Python的Pygame库&a…

2023年前端流行什么技术和框架了?

Web前端三大主流框架有React、Vue.js和Angular&#xff0c;由于接触过Vue.js&#xff0c;接下来主讲最新的Vue3.0&#xff01; Vue3.0作为最新版本的Vue.js框架&#xff0c;拥有更强大的性能和更丰富的功能&#xff0c;为低代码开发平台注入了全新的活力。而JNPF快速开发平台作…

Anchor DETR

Anchor DETR(AAAI 2022) 改进&#xff1a; 提出了基于anchor的对象查询提出Attention变体-RCDA 在以前DETR中&#xff0c;目标的查询是一组可学习的embedding。然而&#xff0c;每个可学习的embedding都没有明确的意义 &#xff08;因为是随机初始化的&#xff09;&#xff…

2024年天津专升本文化课考试大纲发生了哪些变化

2024年天津专升本文化课考试语文、数学、计算机、英语最新大纲发生了哪些变化 高职升本科《计算机应用基础》大纲更改详解:新增计算机发展新技术、win7变更为 win10、word2010变为word2019、 新 增其他常用功能模块、Excel2010变 更为Excel2019、新增演示文稿制作软件PowerPoi…

iPhone15线下购买,苹果零售店前门店排长队

今年的苹果新品发布会于北京时间 9 月 13 日凌晨举行&#xff0c;并于 9 月 15 日&#xff08;周五&#xff09;开启订购&#xff0c;9 月 22 日&#xff08;周五&#xff09;起正式发售。 据多位网友反馈&#xff0c;首批苹果 iPhone15 系列手机、Apple Watch Ultra 2 / Seri…

VBA技术资料MF59:从二维变体数组中删除一行数据

【分享成果&#xff0c;随喜正能量】小小的善业&#xff0c;能赢来大的利益&#xff0c;小小的恶业&#xff0c;同样也能招致严重的后果。这正如古语所云&#xff1a;“莫以善小而不为&#xff0c;莫以恶小而为之。。 我给VBA的定义&#xff1a;VBA是个人小型自动化处理的有效…

【数据库】Sql Server 2022通过临时表和游标遍历方式逻辑处理获取目标数据

2023年&#xff0c;第39周。给自己一个目标&#xff0c;然后坚持总会有收货&#xff0c;不信你试试&#xff01; 今天有个小伙伴咨询一个Sql Server处理数据的问题&#xff0c;刚好重温下SqlServer临时表和游标的知识点 目录 一、需求点描述二、临时表2.1、局部临时表&#xff…

计算机网络相关知识点

谈一谈对OSI七层模型和TCP/IP四层模型的理解&#xff1f; 这两种模型都是网络通信中重要的参考模型,他们的设计和功能有一些区别。 首先OSI&#xff0c;OSI七层模型&#xff0c;也被称为开放系统互联参考模型&#xff0c;是一种在国际标准化组织&#xff08;ISO&#xff09;中…

网络知识——局域网和交换机

定义&#xff1a; 局域网&#xff08;Local Area Network&#xff0c;简称LAN&#xff09;是指在某一区域内由多台计算机互联成的计算机组。广域网&#xff08;Wide Area Network&#xff0c;简称WAN&#xff09;是指跨越单个建筑物或大型园区&#xff0c;连接分布在特定地理区…

2023 Sui Builder House全球之旅圆满收官

2023年的最后一场Builder House于上周在新加坡举行&#xff0c;包括主题演讲、小组讨论和研讨会等聚焦Sui的现在和未来的活动。其中&#xff0c;zkLogin是本次活动的最大亮点。作为一种新的Sui原语&#xff0c;zkLogin允许用户使用Web2身份验证创建帐户&#xff0c;有望推动大规…

计算机网络常见问题

1.谈一谈对OSI七层模型和TCP/IP四层模型的理解&#xff1f; 1.1.为什么要分层&#xff1f; 在计算机中网络是个复杂的系统&#xff0c;不同的网络与网络之间由于协议&#xff0c;设备&#xff0c;软件等各种原因在协调和通讯时容易产生各种各样的问题。例如&#xff1a;各物流…

通过 BigQuery 中的 11 个新链增强 Google Cloud 的区块链数据服务

2018 年初&#xff0c;Google Cloud 与社区合作&#xff0c;通过BigQuery 公共数据集实现区块链数据民主化&#xff1b;2019 年&#xff0c;又扩展了六个数据集&#xff1b;今天&#xff0c;我们在 BigQuery 公共数据集中添加了 11 个最受欢迎的区块链预览版。我们也在对该程序…

windbg -I之后如何恢复原有的

直接运行了一下windbg -I&#xff0c;抓取了注册表行为&#xff0c;然后这里记录一下&#xff0c;方便翻阅。 抓取到的windbg的注册表 计算机\HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\AeDebug\Debugger 将值改为 "C:\WINDOWS\system32\vsji…

Linux:进程概念的引入和理解

文章目录 进程的初步理解进程的实质理解查看进程 前面对操作系统有了一个基础的认知&#xff0c;从中得出的最重要的一个思想是&#xff0c;在认识一个新事物前要先描述&#xff0c;再组织&#xff0c;有了这样的思想也可以用于学习进程的概念 进程的初步理解 有了前面的思想…

三维模型3DTile格式轻量化在三维展示效果上的重要性分析

三维模型3DTile格式轻量化在三维展示效果上的重要性分析 三维模型3DTile格式轻量化在三维展示效果上扮演着至关重要的角色。随着计算机图形学和虚拟现实技术的不断发展&#xff0c;我们已经可以创建和渲染非常精细和复杂的三维模型&#xff0c;以实现逼真的视觉效果。然而&…

3D大模型如何轻量化?试试HOOPS Communicator,轻松读取10G超大模型!

随着计算机技术的不断发展&#xff0c;3D模型在各行各业中的应用越来越广泛。然而&#xff0c;随着模型的复杂性和规模不断增加&#xff0c;处理和浏览超大型3D模型变得越来越具有挑战性。本文将探讨如何轻量化3D大模型&#xff0c;以及如何使用HOOPS Communicator来读取和浏览…

IC芯片测试:如何对芯片静态功耗进行测试?

静态功耗也叫静态电流&#xff0c;是指芯片在静止状态下的电流或者是指芯片在不受外界因素影响下自身所消耗的电流。静态功耗对于芯片来说是衡量一款芯片的功耗与效率非常重要的指标。 传统手动测试静态功耗只需在芯片的输入端串上一台万用表&#xff0c;然后对芯片各个端口添加…

C语言 指针 模拟排序函数 指针数组笔试题上

目标&#xff1a;使用【冒泡排序】的算法&#xff0c;模拟一个排序函数&#xff0c;可以排序任意类型的数据 void print_arr(int arr[], int sz)//打印函数 只能接受整型数组 {int i 0;for (i 0; i < sz; i){printf("%d ", arr[i]);}printf("\n"); }…

5.数学公式中-符号加粗

在 LaTeX 中&#xff0c;\boldsymbol 命令用于将数学公式中的符号或字母加粗显示&#xff0c;以突出显示它们或强调它们的重要性。通常&#xff0c;这个命令用于加粗矢量、矩阵、符号等。 要使用 \boldsymbol&#xff0c;您需要在数学模式中&#xff08;例如&#xff0c;在 \[…