【代码随想录第三天】

代码随想录算法训练营第三天--移除链表元素、设计链表、反转链表 【代码】代码随想录算法训练营第三天--链表。 阅读详情

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

第一次试着写博客,随便写写。

题目一:移除链表元素

删除链表中等于给定值 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 输出:[]

本题可以创建一个哨兵节点temphead(保存值为-1),让temphead的next指向head。
由于需要实际变化过后的head,因此返回temphead.next而不是不动的head.
使用两个指针before和 p 一前一后移动,删除元素时用before和p.next跳过p指向的节点。

class Solution {
    public ListNode removeElements(ListNode head, int val) {
        if(head == null)
        {
            return head;
        }
        ListNode temphead = new ListNode(-1,head);
        ListNode p = head;
        ListNode before = temphead;
        while(before.next != null)
        {
            if(val == p.val)
            {
                before.next = p.next;
            }else{
                before = p;
            }
            p = p.next;
        }
        return temphead.next;
    }
}

注意:
c++在堆区申请内存后仍需delete手动回收,而java中有虚拟机内存回收机制,不用手动回收。
c++会使用 (*p).next 或 p->next 的形式解引用,而java是在调用对象,直接 p.next 即可。
(用java而不是c++之后,感觉以前写链表用c++被指针和引用搞的云里雾里,用java结果能理解记住了,真的奇怪)

题目二:链表实现(java,单链表)

实现过程没有什么大坑,不过有几点需要注意:
1.可以将节点和列表实现用两个类分开,有助于代码简洁;
2.数组可通过下标查找或遍历元素,java的链表遍历可直接在对象中插入index属性以计数。
同时,这也意味着,可以不用靠节点指针或者迭代器遍历链表,直接for循环就行。
3.无论是头插法还是尾插法,都可统一成相同的插入方法而使用不同的参数。可以调用另外的插入函数。
4.注意index边界和空指针问题。
(个人实现时出现了大问题,就不贴出来了,下面是标答)

//单链表
class ListNode {
    int val;
    ListNode next;
    ListNode(){}
    ListNode(int val) {
        this.val=val;
    }
}
class MyLinkedList {
    //size存储链表元素的个数
    int size;
    //虚拟头结点
    ListNode head;

    //初始化链表
    public MyLinkedList() {
        size = 0;
        head = new ListNode(0);
    }

    //获取第index个节点的数值,注意index是从0开始的,第0个节点就是头结点
    public int get(int index) {
        //如果index非法,返回-1
        if (index < 0 || index >= size) {
            return -1;
        }
        ListNode currentNode = head;
        //包含一个虚拟头节点,所以查找第 index+1 个节点
        for (int i = 0; i <= index; i++) {
            currentNode = currentNode.next;
        }
        return currentNode.val;
    }

    //在链表最前面插入一个节点,等价于在第0个元素前添加
    public void addAtHead(int val) {
        addAtIndex(0, val);
    }

    //在链表的最后插入一个节点,等价于在(末尾+1)个元素前添加
    public void addAtTail(int val) {
        addAtIndex(size, val);
    }

    // 在第 index 个节点之前插入一个新节点,例如index为0,那么新插入的节点为链表的新头节点。
    // 如果 index 等于链表的长度,则说明是新插入的节点为链表的尾结点
    // 如果 index 大于链表的长度,则返回空
    public void addAtIndex(int index, int val) {
        if (index > size) {
            return;
        }
        if (index < 0) {
            index = 0;
        }
        size++;
        //找到要插入节点的前驱
        ListNode pred = head;
        for (int i = 0; i < index; i++) {
            pred = pred.next;
        }
        ListNode toAdd = new ListNode(val);
        toAdd.next = pred.next;
        pred.next = toAdd;
    }

    //删除第index个节点
    public void deleteAtIndex(int index) {
        if (index < 0 || index >= size) {
            return;
        }
        size--;
        if (index == 0) {
            head = head.next;
        return;
        }
        ListNode pred = head;
        for (int i = 0; i < index ; i++) {
            pred = pred.next;
        }
        pred.next = pred.next.next;
    }
}

题目三:206反转链表

如果再定义一个新的链表,实现链表元素的反转,其实这是对内存空间的浪费。
其实只需要改变链表的next指针的指向,直接将链表反转 ,而不用重新定义一个新的链表.

class Solution 
{
    //iteration
    public ListNode reverseList(ListNode head) {
        ListNode pre = null;
        ListNode cur = head;
        ListNode temp = null;
        while(cur != null)
        {
            temp = cur.next;//预先指向后一个节点
            cur.next = pre;
            pre = cur;
            cur = temp;
        }
        return pre;
    }
}

用迭代法实现反转。
注意这里实际用了三个指针实现反转:
pre:previous,指前面指针; cur:current,指当前指针;
pre和cur是双指针,让pre一上来指向空而不是head可以规避特殊情况的判定。(确实一上来让pre指向head还挺麻烦的)
temp得提前保存cur原来应该指向的下一个节点(不然cur没的指向了)。
最后返回pre,为新链表的头节点。此时cur指向空。

注意迭代法的一次迭代:每次判定cur不为空,之后进行pre和cur赋值的操作,将cur赋给pre,temp赋值给cur.这是每一次迭代要求的,也是每一层递归时应该等价实现的内容。

用递归法实现反转。

class Solution 
{
    //recursion
    public ListNode reverseList(ListNode head) {
	    return reverse(null, head);
	    //起始条件,剩下的交给reverse递归解决
    }
    public ListNode reverse(ListNode pre, ListNode cur)
    {
	    if(cur == null)//边界条件
	    {
		    return pre;
	    }
	    ListNode temp = cur.next;
	    cur.next = pre;
	    //如下递归的写法,其实就是做了这两步
        // pre = cur;
        // cur = temp;
		reverse(cur, temp);
		//理解这一步是关键
    }
}

唯一的关键是reverse()嵌套调用reverse时。里面的reverse()功能对标了迭代法的每一次迭代赋值。迭代时将cur赋给pre,temp赋值给cur,实质实现的是节点交换顺序。同样,每次调用reverse时也同样在实现此功能,实现交换。因此子递归调用reverse(),形参为cur和temp,将它们实现交换(实质我们也确实在这样做)。
时间复杂度: O(n), 递归处理链表的每个节点
空间复杂度: O(n), 递归调用了 n 层栈空间

还有另外一种与双指针法不同思路的递归写法:从后往前翻转指针指向。很有意思。

// 从后向前递归
class Solution 
{
    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;
    } 
}
【Proteus仿真】用24C04与1602LCD设计的简易加密电子密码锁 阅读详情

相关推荐

手把手教你用ZYNQ PS端GPIO模拟SPI驱动OLED屏幕(附Vivado工程)

本文详细介绍了如何利用ZYNQ PS端的EMIO功能,通过GPIO模拟SPI协议驱动SSD1306 OLED屏幕。从Vivado工程配置、SPI协议软件实现到SSD1306驱动开发,提供了完整的解决方案和优化技巧,适合嵌入式开发者快速上手。

weixin_30776545的博客 130

代码随想录算法训练营第三天

注意:两步删除中的第一步等同于创造一个与传入值不同的链表头,第二步删除与虚拟头的删除方式一样。其中删除操作不是简单的遍历所有链表就可以,而是通过当前元素的下一个元素来判断,因为必须要保证链表的连续,使得当前元素有下一个需要连接的元素。//删除非头结点中相同的。//删除头结点中相同的。//使用两步删除相同元素的节点。递归真是人能想出来的吗?//使用虚拟头的方法。

qq_45903392的博客 972

医用超声图像模拟系统算法:空间分辨率详解

医用超声图像模拟系统中的空间分辨率,是连接物理原理、信号处理算法和最终图像质量的桥梁。通过精确模拟从声场发射、组织相互作用到信号接收和图像重建的全链条过程,并运用先进的波束形成、解卷积和超分辨率算法,我们可以不断逼近并突破物理极限,为开发下一代高分辨率超声成像系统提供强大的算法验证平台和数据集来源。未来的趋势将是更高保真度的物理模拟、更智能的自适应算法与数据驱动方法的深度融合。

alxraves的博客 702

代码随想录训练营第三天

链表是一种通过指针串联在一起的线性结构,每一个节点由两部分组成,一个是数据域一个是指针域(存放指向下一个节点的指针),最后一个节点的指针域指向null(空指针的意思):下面就是单链表。

m0_52827625的博客 365

手机Camera硬件电路设计:从电源管理到信号完整性的实战解析

本文深入解析了手机Camera硬件电路设计的核心挑战与实战经验,重点聚焦于电源管理与信号完整性两大基石。文章详细阐述了AVDD、DVDD、IOVDD和AFVDD四路电源的差异化设计要点与噪声控制策略,并剖析了MIPI等高速信号通道的完整性设计原则,为硬件工程师提供了从理论到PCB布局布线的完整实战指南。

weixin_28308325的博客 251

【STM32H7实战】SDMMC总线优化与FatFs文件系统高效读写技巧

本文详细介绍了STM32H7中SDMMC总线优化与FatFs文件系统高效读写技巧,包括时钟配置、DMA传输、缓存策略等关键优化点。通过实测数据对比,展示了从2.7MB/s提升至11.8MB/s读取速度的优化效果,适用于需要高性能SD卡读写的嵌入式开发场景。

e6f7g8h9i的博客 484

代码随想录算法训练营第三天| 206.反转链表

这个题目我主要是对代码中的循环部分进行了理解,其实有点像需要交换两个瓶子里的水需要三个瓶子,所以在循环过程中可以看到实际上是有三个指针的,还有我想强调一点的是pre是初始化的None,而不是链表尾巴的None。以下是我理解循环时画的图。

OC_jj的博客 189

ubuntu 20.04系统离线安装nfs

ubuntu环境下,离线安装nfs

m0_62464865的博客 2244

代码随想录算法训练营(64期)第三天

三种方法:用原来的链表移除、使用虚拟头节点、递归。

qq_22954713的博客 201

硬件单板类机考复习提纲

6、 功率晶体管低导通损耗时处于的状态(饱和状态、放大状态、截止状态)(放大器的采样频率特性)总结:元器件特性(电阻、电容、二极管、三极管、晶体、晶振、MOS、磁珠等)信号质量问题产生根因(单调性、边沿过缓、毛刺、回沟、抖动等)3、 几种电容容量范围大小(超级电容、钽电容、陶瓷电容、铝电容)66、背板连接器接触设计的接触顺序(先导向、再地针、最后信号针)28、逻辑电平接口的特性(CMOS、TTL、ECL、PECL)76、差分电平(lvpecl、RS-422/485、cml)

2303_79562407的博客 1万+

Python实战:5分钟搞定N-CMAPSS航空发动机数据集解析(附完整代码)

本文提供了一份针对N-CMAPSS航空发动机数据集的快速解析实战指南。通过Python的h5py库,详细演示了如何读取HDF5文件结构、理解数据分类(如传感器、健康参数、场景描述符)并加载为Pandas DataFrame。文章还澄清了数据集中常见的变量数量疑惑,并给出了从数据加载到构建剩余使用寿命预测模型预处理流水线的完整代码,帮助工程师和研究人员高效入门航空发动机预测性维护分析。

weixin_29057065的博客 422

代码随想录第三天

依然三道题理解链表!

kawhixiao的博客 134

路由三大分类:直连路由、静态路由、动态路由

直连路由、静态路由和动态路由各有其独特的特点和适用场景。直连路由适用于简单的直接连接网络,静态路由提供了精确的路径控制,而动态路由则在大型复杂网络中展现出强大的适应性和自动化能力。了解和掌握这三种路由类型的配置和管理,对于网络管理员来说,是确保网络高效、安全运行的重要技能。

网络技术联盟站 4698

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

但我总觉得这样浪费了空间,并且题目还说了可以用递归的方式去实现,因此花了近四十分钟去想递归的解法,之前算法课我觉得已经通透地掌握了递归,也就是把解法建立在递归的函数之上,但这道题一直没想出来咋递归而且看了代码随想录的递归之后还是百思不得其解,信心受挫!代码随想录提供的改变链表的next指针的指向,直接将链表反转的算法很有启发,在此基础上完成了递归的算法,但我一直无法理解这种递归,感觉像是为了递归而递归。:真正实现的时候由于c++不够熟练,花了相当长的时间去实现算法,但其实思路和代码随想录一致。

zhuabazhuabahuo的博客 2118

计算机控制技术及应用

《计算机控制技术及应用》通过总结作者的科研成果和吸收国内外的先进理论、方法和技术,以计算机控制系统的网络化、开放化、智能化和集成化发展趋势为主线索,主要介绍计算机控制系统的基本概念和计算机控制系统的典型形式,计算机控制系统的数学描述与基本分析方法,以及数字PID控制器、最少拍控制系统、达林算法、状态变量设计法等设计方法及其各种改进算法。重点突出计算机控制系统输入输出通道接口的设计方法和典型控制系统的设计案例与实现方法等。

文档:亲测可用解决vnc灰屏,黑屏,鼠标大黑叉情况

主要解决vnc-viewer灰屏,黑屏,鼠标大黑叉等现象,详细见文档。

代码随想录打卡第三天|203.移除链表元素,设计链表,206. 反转链表

力扣打卡

weixin_56718399的博客 452

NTscan扫描工具

ntscan是一个扫描器,可以扫描没有密码和弱密码的共享,先到配置文件中填写猜测的用户名和密码,扫描过程中右侧出现的是扫描日志。

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

代码随想录

tancxiaohei23的博客 1095

SAP B1中文培訓教材_SDK

公司内部培训资料,对开发工具 ,DIAPI, UIAPI,Add-ON有详细解说

代码随想录打卡第三天-链表

本题一上来给我的难点就在于需要自己构造节点类和链表,因工作中很少使用链表,已经忘记如何初始化一个链表,罪过。此外就是对下标index的判断,即插入删除是节点指针应当走到哪里然后操作节点,想明白这里后这道题即可迎刃而解。本题难点在于对头指针的操作,引入虚拟头节点后解决这一问题,即使得头节点的操作和普通节点保持了一致。

weixin_47742046的博客 225

代码随想录打卡第三天

使用的是虚拟头节点的方法。假定没有虚拟头节点,使用原来的链表结构直接操作。如果有了虚拟头节点,那么对于所有节点,包括真实的头节点,链表操作时相同的。注意 dummy node.next才是头节点,所以我们要返回的时dummy node.next。并且在链表的题目中,我们不直接操作原链表,而是新建立一个节点用于遍历操作,避免原来的那个节点在遍历中发生改变。根据前面一道题目的启发 我们可以使用头插法,及头部添加节点的方式,只需要遍历一次原来的链表就可以了。这个题目也很简单,注意虚拟头节点的使用,简化操作。

m0_60633015的博客 337

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

链表是一种物理存储结构上非连续存储结构,数据元素的逻辑顺序是通过链表中的引用链接次序实现的。

Hsusan的博客 382

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

这道题对于我之前来说也是“老大难”的题目,看了很久也是没有明白题目到底是什么意思,就算是对照着答案看也是半天才明白应该怎么去做,其实说到底就是写链表的五个接口,分别是。虽然这道题已经通过很多次了,但是还是需要说一下思路。zaccheo打卡代码随想录第三天。首先就是需要初始化链表。

AKA_ZHANG的博客 494
下一篇: 代码随想录 day4 第二章 链表part02
TechyUnique
博客等级 码龄5年 201粉丝 21原创
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值