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

代码随想录算法训练营第三天| 203.移除链表元素 707.设计链表| 206.反转链表 建议: 本题最关键是要理解 虚拟头结点的使用技巧,这个对链表题目很重要。思路:1.直接使用原来的链表进行删除操作。 2.设置一个虚拟头结点在进行删除操作题目链接:. - 力扣(LeetCode)视频链接:手把手带你学会操作链表 | LeetC de:203.移除链表元素_哔哩哔哩_bilibili文章链接:手把手带你学会操作链表 | LeetCode:203.移除链表元素_哔哩哔哩_bilibili具体实现:定义一个cur = head 的结点,遍历链表,每次遍历时 cur.val 和 阅读详情

题目和思路:

链表基础:

复习定义链表结点:

class ListNode:
    def __init__(self, val, next=None):
        self.val = val
        self.next = None

203.移除链表元素 

循环遍历链表,每次循环需要查看next的val值,如果等于目标值,将当前节点的next指向再后面一个节点,跳过当前节点的next。由于每次查看的下一个节点的目标值,所以定义虚拟头节点,用于防止头节点的val值等于目标值。最终返回虚拟头节点的next即可。代码如下:

class Solution:
    def removeElements(self, head: Optional[ListNode], val: int) -> Optional[ListNode]:
        flag = ListNode(next = head)
        cur = flag

        while cur.next:
            if cur.next.val == val:
                cur.next = cur.next.next
            else: cur = cur.next

        return flag.next

实际写代码过程中,犯了如下错误:

while cur.next:
    if cur.next.val == val:
        cur.next = cur.next.next
    cur = cur.next

 这样写错误的原因是,不管删没删cur.next,cur都会向后移动一次,那么假如cur.next被删除,cur会直接跳到cur.next.next而不会管cur.next.next是否是目标值也不会检查它是不是None,会漏删、以及链表尾部是目标值时会报NoneType没有next方法的错误。所以必须只有不删cur.next的时候才能往后移动cur,删除了就原地呆着等下一轮循环。

707.设计链表

很糟心,代码如下:

class ListNode:
    def __init__(self, val = 0, next = None):
        self.val = val
        self.next = next

class MyLinkedList:

    def __init__(self):
        self.head = ListNode() #这是一个虚拟头节点

    def get(self, index: int) -> int:
        if index < 0: return -1
        cur = self.head.next
        cnt = 0
        while cur:
            if cnt == index:
                return cur.val
            else:
                cur = cur.next
                cnt += 1
        return -1

    def addAtHead(self, val: int) -> None:
        node = ListNode(val)
        node.next = self.head.next
        self.head.next = node

    def addAtTail(self, val: int) -> None:
        cur = self.head
        while cur.next:
            cur = cur.next
        cur.next = ListNode(val)

    def addAtIndex(self, index: int, val: int) -> None:
        node = ListNode(val)
        cnt = 0
        cur = self.head

        while cur.next:
            if cnt == index:
                node.next = cur.next
                cur.next = node
                break
            else:
                cur = cur.next
                cnt += 1
        
        if cnt == index:
            cur.next = node

    def deleteAtIndex(self, index: int) -> None:
        cur = self.head
        cnt = 0
        while cur.next:
            if cnt == index:
                cur.next = cur.next.next
                break
            else:
                cur = cur.next
                cnt += 1

第一遍完全错误的点是,把初始化的head当成了头节点,结果直接头部插入节点直接会变成1->0(head),然后把head赋给了1,整一个理解错误。

第二遍错的点是在插入环节,node插在cur和cur.next之间,我写成了node.next =cur.next.next, cur.next = node.next,整段垮掉。

第三遍错在delete,本题跟上题有区别,本题删除的是index处的值,没有在if条件下删除后面加break跳出循环,导致把后面全删完了...

这里贴一段比较好的代码,下次可以参考:

class ListNode:
    def __init__(self, val=0, next=None):
        self.val = val
        self.next = next

class MyLinkedList:
    def __init__(self):
        self.size = 0
        self.head = ListNode(0)  # Sentinel node as pseudo-head

    def get(self, index):
        if index < 0 or index >= self.size:
            return -1
        current = self.head
        for _ in range(index + 1):
            current = current.next
        return current.val

    def addAtHead(self, val):
        self.head.next = ListNode(val, self.head.next)
        self.size += 1

    def addAtTail(self, val):
        self.size += 1
        new_node = ListNode(val)
        current = self.head
        while current.next:
            current = current.next
        current.next = new_node

    def addAtIndex(self, index, val):
        if index > self.size:
            return
        index = max(0, index)
        self.size += 1
        pred = self.head
        for _ in range(index):
            pred = pred.next
        to_add = ListNode(val)
        to_add.next = pred.next
        pred.next = to_add

    def deleteAtIndex(self, index):
        if index < 0 or index >= self.size:
            return
        self.size -= 1
        pred = self.head
        for _ in range(index):
            pred = pred.next
        pred.next = pred.next.next

for循环的好处是到位置就停,然后开始操作!学!

206. 反转链表

1、双指针法,左指针指向左边反转好的内容,右指针指向还没反转的部分。假如右指针指到None,迭代终止了,返回左指针即可。如果右指针不为None,那么先记录一下cur.next,记为temp。然后将右指针指向的节点连接到左指针指向的节点,cur.next = prev,然后把左指针移动到cur,cur移动到temp进行下一轮迭代。代码如下:

class Solution:
    def reverseList(self, head: Optional[ListNode]) -> Optional[ListNode]:
        prev, cur = None, head
        while cur:
            temp = cur.next
            cur.next = prev
            prev = cur
            cur = temp
        return prev

2、递归法一(尾递归):根据上述双指针法写的递归,需要新建一个函数,reverse,传入左指针和右指针的指向,原主函数用于初始化。递归终止的情况就是右指针指向None,左指针就指向了反转好的头节点,递归结束反转完毕。

一般情况下,也就是从头开始,把右指针的next保存一下,把右指针指向左指针节点,完成了局部反转,返回调用自身,相当于把左指针和右指针向右移了一下,只不过是用cur和temp表示。

举个栗子:假设我们有一个链表1->2->3->None,我们要使用这个递归方法来反转它。

  • 初始调用
    • reverse(1, None)
    • cur 指向 1, prev 是 None
  • 递归调用层级 1
    • 在 reverse 函数内部:
      • temp = cur.next 保存了 2
      • cur.next = prev 使得 1 指向 None(断开 1 -> 2,现在 1 -> None)
      • 调用 reverse(2, 1)
  • 递归调用层级 2
    • reverse(2, 1)
    • cur 指向 2, prev 指向 1
    • 在 reverse 函数内部:
      • temp = cur.next 保存了 3
      • cur.next = prev 使得 2 指向 1(断开 2 -> 3,现在 2 -> 1 -> None)
      • 调用 reverse(3, 2)
  • 递归调用层级 3
    • reverse(3, 2)
    • cur 指向 3, prev 指向 2
    • 在 reverse 函数内部:
      • temp = cur.next 保存了 None
      • cur.next = prev 使得 3 指向 2(现在 3 -> 2 -> 1 -> None)
      • 调用 reverse(None, 3)
  • 递归调用层级 4
    • reverse(None, 3)
    • cur 是 None, prev 指向 3
    • 基本情况满足,返回 prev,即 3

class Solution:
    def reverseList(self, head: Optional[ListNode]) -> Optional[ListNode]:
        return self.reverse(head, None)
    
def reverse(self, cur, prev):
        #基本情况,右指针指向None,直接返回左指针就是已经反转好的链表。
        if cur == None:
            return prev        
        #递归反转
        temp = cur.next
        cur.next = prev
        return self.reverse(temp,cur)

3、递归法二:(头递归):基本情况是当前的链表只有一个节点或者是空,那就直接返回原链表head。递归地反转head之后的节点,返回为reversed_head(这是反转好的头节点,也就是原链表的尾节点!!),这时候head.next是反转后最后一个节点,把他指向head,再给head断开连接,就完成了反转,这时只要继续返回reversed_head即可。

举个栗子:假设我们有一个链表1->2->3->4->None,我们要使用这个递归方法来反转它。

  1. 递归调用层级 1

    • head 指向 1
    • 递归调用 reverseList 以反转 2 -> 3 -> 4 -> None
  2. 递归调用层级 2

    • head 指向 2
    • 递归调用 reverseList 以反转 3 -> 4 -> None
  3. 递归调用层级 3

    • head 指向 3
    • 递归调用 reverseList 以反转 4 -> None
  4. 递归调用层级 4

    • head 指向 4
    • 到达基本情况:head.next 是 None,所以返回 head(即 4)

  递归返回并反转链接

  1. 返回到递归调用层级 3

    • head 是 3
    • 执行 head.next.next = head(即 4 -> 3)
    • 设置 head.next = None(断开 3 -> 4,现在 4 -> 3 -> None)
    • 返回新的头节点 4
  2. 返回到递归调用层级 2

    • head 是 2
    • 执行 head.next.next = head(即 3 -> 2)
    • 设置 head.next = None(断开 2 -> 3,现在 4 -> 3 -> 2 -> None)
    • 返回新的头节点 4
  3. 返回到递归调用层级 1

    • head 是 1
    • 执行 head.next.next = head(即 2 -> 1)
    • 设置 head.next = None(断开 1 -> 2,现在 4 -> 3 -> 2 -> 1 -> None)
    • 返回新的头节点 4
class Solution:
    def reverseList(self, head: Optional[ListNode]) -> Optional[ListNode]:
        # 基本情况:空链表或只有一个节点
        if head is None or head.next is None:
            return head

        # 递归反转除了头节点外的子链表
        reversed_head = self.reverseList(head.next)

        # 将原始头节点连接到新反转链表的末尾
        head.next.next = head
        head.next = None

        # 返回新的头节点
        return reversed_head

今日总结:

以前本科时候就很讨厌链表,因为常常出错。但是逃避是没有用哒!尽管今天还是很多错误,但是找出了错误的原因,并且从这些错误中吸取到了教训,下次也许会好一些。

尽管今天没有额外的题目,但是第二题和第三题让我头大。第二题主要是对类和链表的理解有问题,太久没有写代码生疏了很多很多,一遍一遍回滚直到AC,在debug中成长...

第三题双指针方法很容易就写出来了,对两种递归方法一直没有理清头绪。两种方法截然相反,实在很影响理解。第一种尾递归实际就是迭代,第二种头递归是在递归返回的时候进行反转操作,有很大区别,理解head.next.next=head成为关键。

代码随想录算法训练营第三天|LeetCode203.移除链表元素、LeetCode707.设计链表、LeetCode206.反转链表 给你一个链表的头节点head和一个整数val,请你删除链表中所有满足的节点,并返回。这里以链表1 4 2 4来举例,移除元素4:如果使用C++,C的话,记得从内存中删除两个移除的节点如果使用Java、python的哈就无需手动管理内存了二者的主要区别在于党移除头结点时的操作,先来看直接使用原来的链表进行删除操作:移除头结点和移除其他节点的操作是不一样的,因为链表的其他节点都是通过前一个节点来移除当前节点,而头结点没有前一个节点。 阅读详情

相关推荐

机械臂电机力矩计算

设计 6 轴机械臂时,电机力矩计算是确保机械臂负载能力、运动精度和安全性的核心环节,需围绕和两大核心展开,结合机械臂结构参数(如关节长度、质量分布)、负载需求(如末端负载重量、惯性)和运动参数(如加速度、角速度)逐步推导。

ZPC8210的博客 1857

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

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

zhuabazhuabahuo的博客 2118

AI量化交易工作台Vibe-Trading:用自然语言驱动策略回测与多智能体研究

量化交易通过数学模型和计算机程序执行投资决策,其核心在于将市场规律转化为可验证的策略。传统量化开发涉及数据获取、策略编写、回测验证等复杂工程,对非编程背景的从业者构成较高门槛。随着大语言模型技术的发展,自然语言交互正成为降低技术使用难度的关键。Vibe-Trading项目正是这一趋势的实践,它将金融工程任务封装为可调用的工具与技能,允许用户通过自然语言指令直接驱动策略回测、因子研究和投资组合分析。其技术价值在于构建了一个模块化的AI Agent框架,通过ReAct推理框架协调多个专项技能,并创新性地引入多智

weixin_28695161的博客 1567

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

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

Hsusan的博客 382

VMD-CNN-BiLSTM-Attention预测模型 —— 数学模型介绍&完整实例代码

想解决电力负荷预测中的非线性、非平稳难题?这篇博客介绍了一种创新混合模型,结合变分模态分解(VMD)和CNN-BiLSTM-Attention深度学习架构,实现超高精度预测! ✨ 核心亮点: ✅ VMD分解:有效分离复杂负荷信号,提取关键频率特征 ✅ 混合深度学习:CNN捕捉局部模式 + BiLSTM学习长时序依赖 + 注意力机制聚焦关键时段 ✅ 端到端优化:从数据预处理(滑动窗口、归一化)到模型训练(MSE损失+Adam优化),完整流程公开! ✅ 工业级评估:提供MSE、MAE、MAPE、R²多指标验证

qq_42924330的博客 1653

实战STM32G0驱动DRV8870/AT8870:PWM+DMA精准调速与H桥衰减模式详解

本文详细介绍了如何使用STM32G0单片机结合DRV8870/AT8870电机驱动芯片实现直流有刷电机的精准控制。重点讲解了PWM与DMA结合实现高效调速的硬件配置与软件驱动方法,并深入剖析了H桥快衰减与慢衰减模式的工作原理及应用场景,为嵌入式电机控制项目提供了完整的实战解决方案。

c7d8e9的博客 595

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

一些链表的添加删除操作使用虚拟头结点(具体看题目),不要无脑使用链表结构实际在js中是一个对象(?

weixin_46078957的博客 423

[特殊字符]交通标志检测与分类数据集-智能驾驶系统 地图数据更新 1,886张图片

🚦交通标志检测与分类数据集-智能驾驶系统 地图数据更新 1,886张图片

cver123的博客 2075

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

注:代码随想录网站上的链表题大一上寒假做过,记不清了,这次是重做。203.移除链表元素基础题,有几点需要注意:(1)链表基础语法,以及 cpp 中链表相关知识下面是leetcode对cpp链表的定义,不同于c,有现成的可用的函数,如创建节点并且赋值链表有关题目,一般操控的都是指向节点的指针,一般用 " -> " ,不怎么用 " . "

2301_80094768的博客 454

300Kg载重履带式无人车底盘定制开发技术详解

通过精准的需求分析、科学的方案设计、严格的研发与测试以及完善的交付与培训流程,可以打造出符合客户需求的优质产品。300Kg载重履带式无人车底盘的定制开发,旨在打造一款承载能力强、行驶稳定、适应复杂地形的无人运输平台。根据应用场景选择合适的动力源,并进行性能优化,确保无人车在载重情况下仍能保持稳定的行驶速度和动力输出。根据需求分析结果,设计无人车底盘的总体方案,包括动力系统选择、结构设计、负载管理策略等。进行详细的研发工作,包括零部件的选型与采购、样机的制作与调试等。

专注多旋翼、复合翼无人机技术研究,从事低空经济行业。 958

AD快速上手笔记

本文详细介绍了使用Altium Designer从零创建PCB项目全流程:新建工程、绘制原理图(元件放置、连线、电源端口)、编译检查、生成PCB、布局布线(含铺铜)、DRC检查及输出Gerber与钻孔文件。重点强调了库选择、参数修改、层切换、铺铜设置和生产文件导出规范,确保设计无误,便于顺利下单生产。

qq_53529450的博客 42

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

难度:简单给你一个链表的头节点head和一个整数val,请你删除链表中所有满足的节点,并返回。

wwssdffffggg的博客 344

软件可靠性设计

本文系统介绍了软件可靠性设计与建模的理论框架和实施方法。首先从可靠性定义、核心思想和与建模的关系等理论基础出发,重点阐述了模块化设计、冗余容错、异常处理等六类可靠性设计方法及其技术栈。文章详细分析了可靠性设计在软件生命周期各阶段的应用,并深入探讨了设计与建模的深度结合机制,包括参数影响、验证方法和量化指标。最后提出了覆盖设计、开发、测试和运行四个阶段的落地策略,形成完整的"设计-建模-运行"流程体系。全文强调通过预防性设计和量化建模相结合的方法提升软件系统的可靠性和稳定性。

moton2017的博客 896

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

今天是打卡的第三天,明显感觉到没有前两天热情高涨了哈哈哈,主要是今天第二个那个707卡的人太久了,有点繁琐这道题,希望后面能尽量坚持下去。

m0_53877706的博客 283

数学建模模型总结

这是本人在两年内准备参加数学建模竞赛搜集到的模型资料,已经经过了本人的筛选和整理,希望能够对准备参加数学建模竞赛的学弟学妹们提供一些帮助!

win10 跳过U8环境检测的IE WebControls.rar

win10 安装u8的时候 提示IE WebControls 不通过,这个工具可以欺骗u8的检查。 跳过U8环境检测的IE WebControls。提示导入失败后,重新检测通过。

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

不过我这个有设计思路,可以拆分成很多小题目。看起来这就是一个 笨办法 ……其实没有完全的解决处理问题。单链表 结点的类定义。

m0_72063747的博客 437

jdk-8u144-linux-x64.tar.gz.

该资源为搭建Linux系统Java环境用,资源的后缀为tar.gz格式的压缩包

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

力扣链表203、707、23题

SSaltedFish_tian的博客 331

efm32 入门.pdf

本PDF共计22页,介绍的是操作驱动API,下载与否自己斟酌。

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

链表的题目中重要的就是虚拟头结点边界条件处理(可以自己假设如果只有一个头结点的情况来判断自己的边界情况对不对),执行各种操作(交换,插入……)时temp的临保存,next的不同顺序调用。

U_L_Yxan的博客 2247

代码随想录算法训练营第三天|Leetcode203 移除链表元素、Leetcode707 设计链表、Leetcode206 反转链表

双向链表中不仅有指向后一个节点的指针,还有指向前一个节点的指针。而链表通过不连续的储存方式,自适应内存大小,以及指针的灵活使用,巧妙的简化了上述的内容。这个链接指向链表中的下一个节点,而最后一个节点的链接域则指向一个空值。题目描述:给你一个链表的头节点 head 和一个整数 val ,请你删除链表中所有满足 Node.val == val 的节点,并返回 新的头节点。对于数组而言存在一个最大的缺点,就是我们的插入和删除时需要移动大量的元素,需要消耗大量的时间,同时必须为数组开足够的空间,否则有溢出风险。

Demok123的博客 925

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

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

北天的博客 1210

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

链表1:203.移除链表元素、707.设计链表 、206.反转链表

wangaijun233666的博客 140

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

记忆点:1.建立虚拟头节点:最后return head的时候可以直接return dummy.next;2.head作为解放出的节点,可以去遍历整个链表,在正常情况下,prev和head一同遍历链表,出现head->val == val;时,prev->next = head->next;

lampp0st的博客 224

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

打卡第三天~今天是链表专题~

qq_53009915的博客 1833

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

链表是一种通过指针串联在一起的线性结构,每一个节点由两部分组成,一个是数据域,一个是指针域(存放指向下一个节点的指针),最后一个节点的指针指向null(空指针)链表的入口节点成为head单链表:指针域只能指向节点的下一个节点。双链表:每一个节点由两个指针域,一个指向下一个节点,一个指向上一个,所以可向前也可向后查询。循环链表:链表首尾相连。可以用来解决约瑟夫环问题。由前两天的数组内容可知,一维数组在内存中是连续分布的,C++的二维数组也是,Java的二维数组内存不连续。

m0_57352861的博客 1079

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

/ 单链表int val;// 节点上存储的元素// 指向下一个节点的指针ListNode(int x) : val(x), next(NULL) {} // 节点的构造函数在python中定义链表,需要先定义一个Node类,然后在定义一个LinkedList来管理这些节点。"""定义链表节点"""self.val = val # 节点存储的值self.next = None # 指向下一个节点的引用,默认为None## 这个类将管理节点,并提供插入、删除、遍历操作"""

qq_58067521的博客 571
上一篇: 代码随想录算法训练营第二天| 977.有序数组的平方、 209.长度最小的子数组、 59.螺旋矩阵II
下一篇: 代码随想录算法训练营第四天| 24. 两两交换链表中的节点、19.删除链表的倒数第N个节点、面试题 02.07. 链表相交、142.环形链表II
LIEBESFREUD
博客等级 码龄9年 372粉丝 80原创
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值