leetcode极速复习版-第二章链表

news2024/11/20 3:22:18

目录

链表 

203.移除链表元素  

 707.设计链表  

 206.反转链表 

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

 19.删除链表的倒数第N个节点  

 面试题 02.07. 链表相交  

链表部分总结


链表 

203.移除链表元素  

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

如果删除的是头结点又该怎么办呢?

这里就涉及如下链表操作的两种方式:

  • 直接使用原来的链表来进行删除操作。
  • 设置一个虚拟头结点在进行删除操作。

头结点如何移除呢,其实只要将头结点向后移动一位就可以,这样就从链表中移除了一个头结点。依然别忘将原头结点从内存中删掉。

设置一个虚拟头结点,这样原链表的所有节点就都可以按照统一的方式进行移除了。

来看看如何设置一个虚拟头。依然还是在这个链表中,移除元素1。 

# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, val=0, next=None):
#         self.val = val
#         self.next = next
class Solution:
    def removeElements(self, head: Optional[ListNode], val: int) -> Optional[ListNode]:
        # 创建虚拟头部节点以简化删除过程
        dummy_head = ListNode(next = head)
        
        # 遍历列表并删除值为val的节点
        current = dummy_head
        while current.next:
            if current.next.val == val:
                current.next = current.next.next
            else:
                current = current.next
        
        return dummy_head.next
 707.设计链表  

在链表类中实现这些功能:

  • get(index):获取链表中第 index 个节点的值。如果索引无效,则返回-1。
  • addAtHead(val):在链表的第一个元素之前添加一个值为 val 的节点。插入后,新节点将成为链表的第一个节点。
  • addAtTail(val):将值为 val 的节点追加到链表的最后一个元素。
  • addAtIndex(index,val):在链表中的第 index 个节点之前添加值为 val  的节点。如果 index 等于链表的长度,则该节点将附加到链表的末尾。如果 index 大于链表长度,则不会插入节点。如果index小于0,则在头部插入节点。
  • deleteAtIndex(index):如果索引 index 有效,则删除链表中的第 index 个节点。

# 看完视频,三处重点
# 一是current.next一定要指向题目要求的第n个节点,而不是current指向第n个节点。这样才好通过
# 改变current.next来改变链表的第n个节点。如果不清楚这一点很容易改成第n-1个节点或者第n+1个
# 节点
# 二是在插入新节点时一定要注意修改指针的顺序。先修改新节点的指针指向
# current.next(newnode.next=current.next),再修改current的指针指向新节点
# (current.next=newnode)。如果顺序反了,先修改current的指针指向新节点,此时就丢失了原
# current.next的指针,就无法让新节点的指针指向正确位置了。
# 三是增删链表元素后一定记得改变size的值
 
#一般先定义dummyhead再定义cur 这俩步骤不可少,记住就完事,漏一个基本就写不对了。
# while(index > 0)可以简写为while(index)
 
class ListNode:
    def __init__(self, val=0, next=None):
        self.val = val
        self.next = next
 
class MyLinkedList():
 
    def __init__(self):
        # self.head = ListNode() # ❗ 注意了,self是一个object,不能是链表本身。self不能作为头节点,要设self.head作为头节点。
        # # 似乎直接把这个head当成dummyhead就可以
        # dummyhead = self.head # 写这里没用
        self.dummyhead = ListNode()
 
        self.size = 0 # 设置一个链表长度的属性,便于后续操作,注意每次增和删的时候都要更新 
        #⭐这一句是抄答案的!
 
    def get(self, indexint) -> int:
        if (index >= 0) and (index < self.size)# ❗if条件里and不能换成&&,后者报错
        # ❗注意不能是index <= self.size,因为index=1时self.size至少为2
            # dummyhead = ListNode(0, self.head) # ❗是ListNode而不是Listnode 注意大小写
            cur = self.dummyhead.next
            while(index > 0):
                cur = cur.next
                index -= 1
            return cur.val
        else:
            return -1
 
    def addAtHead(self, val: int) -> None:
        # newnode = ListNode(val, self.head) # ❓这种表达方式对否,还是说需要先创建新节点再指向self
        # 上行不对。若这么写,相当于每次新节点都指向同一个头节点,多次运行该函数时,并不会“增加”元素,而只是对一个指向head的节点的重新覆盖(不同的val)。
        newnode = ListNode(val)
        # newnode.next = self.head
        # 上行不对。head依然是那个head,没有将head转移到最前面的节点。
        # dummyhead = ListNode(0, self.head)
        newnode.next = self.dummyhead.next
        self.dummyhead.next = newnode
        self.size += 1
 
    def addAtTail(self, val: int) -> None:
        # dummyhead = ListNode(0, self.head)
        newnode = ListNode(val)
        cur = self.dummyhead
        while(cur.next != None):
            cur = cur.next
        # cur.next.val = val # ❓这种表达方式对否,还是说需要先用ListNode创建尾节点然后cur指向尾节点
        # 上行不对。因为此时cur.next是None而不是一个节点。
        cur.next = newnode
        self.size += 1
 
    def addAtIndex(self, indexint, val: int) -> None:
        if (index >= 0) and (index < self.size)# ❗注意不能是index <= self.size,因为index=1时self.size至少为2
            # dummyhead = ListNode(0, self.head)
            newnode = ListNode(val)
            cur = self.dummyhead
            while(index > 0):
                cur = cur.next
                index -= 1
            newnode.next = cur.next
            cur.next = newnode
            self.size += 1
            return # ❗多if分支时建议写return,避免完成一个分支后代码继续往下走
        elif index < 0:
            self.addAtHead(val)
            # self.size += 1 # ❗这时候就不用改变size了因为已经在上面调用的函数内了
            return
        elif index == self.size:  
            self.addAtTail(val)
            # self.size += 1
            return
        else:
            return
 
    def deleteAtIndex(self, indexint) -> None:
        if (index >= 0) and (index < self.size)# ❗注意不能是index <= self.size,因为index=1时self.size至少为2
            # dummyhead = ListNode(0, self.head)
            cur = self.dummyhead
            while (index > 0):
                cur = cur.next
                index -= 1
            cur.next = cur.next.next
            self.size -= 1
 
# Your MyLinkedList object will be instantiated and called as such:
# obj = MyLinkedList()
# param_1 = obj.get(index)
# obj.addAtHead(val)
# obj.addAtTail(val)
# obj.addAtIndex(index,val)
# obj.deleteAtIndex(index)
 206.反转链表 

题意:反转一个单链表。

示例: 输入: 1->2->3->4->5->NULL 输出: 5->4->3->2->1->NULL

首先定义一个cur指针,指向头结点,再定义一个pre指针,初始化为null。

然后就要开始反转了,首先要把 cur->next 节点用tmp指针保存一下,也就是保存一下这个节点。

为什么要保存一下这个节点呢,因为接下来要改变 cur->next 的指向了,将cur->next 指向pre ,此时已经反转了第一个节点了。

class Solution:
    def reverseList(self, head: ListNode) -> ListNode:
        cur = head   
        pre = None
        while cur:
            temp = cur.next # 保存一下 cur的下一个节点,因为接下来要改变cur->next
            cur.next = pre #反转
            #更新pre、cur指针
            pre = cur
            cur = temp
        return pre
 24. 两两交换链表中的节点 

给定一个链表,两两交换其中相邻的节点,并返回交换后的链表。

你不能只是单纯的改变节点内部的值,而是需要实际的进行节点交换。

class Solution:
    def swapPairs(self, head: ListNode) -> ListNode:
        dummy_head = ListNode(next=head)
        current = dummy_head
        
        # 必须有cur的下一个和下下个才能交换,否则说明已经交换结束了
        while current.next and current.next.next:
            temp = current.next # 防止节点修改
            temp1 = current.next.next.next
            
            current.next = current.next.next
            current.next.next = temp
            temp.next = temp1
            current = current.next.next
        return dummy_head.next
 19.删除链表的倒数第N个节点  

给你一个链表,删除链表的倒数第 n 个结点,并且返回链表的头结点。

进阶:你能尝试使用一趟扫描实现吗?

输入:head = [1,2,3,4,5], n = 2 输出:[1,2,3,5] 示例 2:

输入:head = [1], n = 1 输出:[] 示例 3:

输入:head = [1,2], n = 1 输出:[1]

fast首先走n + 1步 ,为什么是n+1呢,因为只有这样同时移动的时候slow才能指向删除节点的上一个节点(方便做删除操作),如图:

fast和slow同时移动,直到fast指向末尾,如题:

删除slow指向的下一个节点,如图:

class Solution:
    def removeNthFromEnd(self, head: ListNode, n: int) -> ListNode:
        # 创建一个虚拟节点,并将其下一个指针设置为链表的头部
        dummy_head = ListNode(0, head)
        
        # 创建两个指针,慢指针和快指针,并将它们初始化为虚拟节点
        slow = fast = dummy_head
        
        # 快指针比慢指针快 n+1 步
        for i in range(n+1):
            fast = fast.next
        
        # 移动两个指针,直到快速指针到达链表的末尾
        while fast:
            slow = slow.next
            fast = fast.next
        
        # 通过更新第 (n-1) 个节点的 next 指针删除第 n 个节点
        slow.next = slow.next.next
        
        return dummy_head.next
 面试题 02.07. 链表相交  

给你两个单链表的头节点 headA 和 headB ,请你找出并返回两个单链表相交的起始节点。如果两个链表没有交点,返回 null 。

图示两个链表在节点 c1 开始相交:

题目数据 保证 整个链式结构中不存在环。

注意,函数返回结果后,链表必须 保持其原始结构 。

示例 1:

示例 2:

我们求出两个链表的长度,并求出两个链表长度的差值,然后让curA移动到,和curB 末尾对齐的位置,此时我们就可以比较curA和curB是否相同,如果不相同,同时向后移动curA和curB,如果遇到curA == curB,则找到交点。如图:

class Solution:
    def getIntersectionNode(self, headA: ListNode, headB: ListNode) -> ListNode:
        curA = headA
        curB = headB
        sizeA = 0
        sizeB = 0
        while curA != None:
            sizeA += 1
            curA = curA.next
        while curB != None:
            sizeB += 1
            curB = curB.next
        
        curA = headA
        curB = headB
        if sizeA > sizeB:
            n = sizeA - sizeB
            while n:
                curA = curA.next
                n -= 1
        elif sizeA < sizeB:
            n = sizeB - sizeA
            while n:
                curB = curB.next
                n -= 1
        
        # while curA.val != curB.val and curA != None:
        # ❗注意是节点的相同而不是值的相同。因此不需要取val属性。否则:
        # 输入:intersectVal = 8, listA = [4,1,8,4,5], listB = [5,0,1,8,4,5],
        #  skipA = 2, skipB = 3
        # while里取val则输出:Intersected at '1'.正确输出:Intersected at '8'
        while curA != curB and curA != None:
            curA = curA.next
            curB = curB.next
        return curA
  1. 环形链表II  

给定一个链表,返回链表开始入环的第一个节点。 如果链表无环,则返回 null。

为了表示给定链表中的环,使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。 如果 pos 是 -1,则在该链表中没有环。

那么相遇时: slow指针走过的节点数为: x + y, fast指针走过的节点数:x + y + n (y + z),n为fast指针在环内走了n圈才遇到slow指针, (y+z)为 一圈内节点的个数A。

因为fast指针是一步走两个节点,slow指针一步走一个节点, 所以 fast指针走过的节点数 = slow指针走过的节点数 * 2:

(x + y) * 2 = x + y + n (y + z)

两边消掉一个(x+y): x + y = n (y + z)

因为要找环形的入口,那么要求的是x,因为x表示 头结点到 环形入口节点的的距离。

class Solution:
    def detectCycle(self, head: Optional[ListNode]) -> Optional[ListNode]:
        fast = head
        slow = head
        while fast != None and fast.next != None:
            fast = fast.next.next
            slow = slow.next
            if slow == fast:
                index1 = fast
                index2 = head
 
                while index1 != index2:
                    index1 = index1.next
                    index2 = index2.next
                return index1

从头结点出发一个指针,从相遇节点 也出发一个指针,这两个指针每次只走一个节点, 那么当这两个指针相遇的时候就是 环形入口的节点。

也就是在相遇节点处,定义一个指针index1,在头结点处定一个指针index2。

链表部分总结

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

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

相关文章

基于Java在线电影评价系统设计实现(源码+lw+部署文档+讲解等)

博主介绍&#xff1a;✌全网粉丝30W,csdn特邀作者、博客专家、CSDN新星计划导师、Java领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精彩专…

【Linux】十分钟理解软硬链接

目录 1.磁盘的物理结构2.磁盘的物理存储结构3.文件系统4.硬链接4.14.2 5.软链接6.三种时间 1.磁盘的物理结构 盘片&#xff1a;一片两面&#xff0c;有一摞盘片。磁头&#xff1a;一面一个磁头&#xff0c;一个磁头负责一面的读取&#xff08;磁头是一起动的&#xff09;。马达…

二叉树 — 返回二叉树最大距离

题目&#xff1a; 给定二叉树头结点head&#xff0c;任何两个节点之间都有距离&#xff0c;求整棵二叉树最大距离。 二叉树如下图所示&#xff0c;假设从x到b&#xff0c;中间节点只能走一次&#xff0c;我们人为规定距离就是整条路径的节点数量&#xff0c;所以距离是3&#x…

Spring Boot 中的 Spring Cloud Gateway

Spring Boot 中的 Spring Cloud Gateway Spring Cloud Gateway 是一个基于 Spring Boot 的网关框架&#xff0c;它提供了一种统一的入口&#xff0c;将所有的请求路由到不同的后端服务中。Spring Cloud Gateway 采用了 Reactive 编程模型&#xff0c;可以处理大量并发请求&…

idea闪退,端口占用处理

1、idea --> Terminal 2、 输入命令 jps 查看进程 3、找到对应的进程&#xff0c;使用 taskkill /pid 端口号 /f 4、 重启项目 &#xff0c;即可

Golang快速鸟瞰

文章目录 引子知识图谱包代理设置关键字数据类型变量struct 和 interface控制语句字符串单引号、双引号、反引号数组与切片字典make和newjson与yaml基本语法指针Channeldeferinit函数类error, panic, recoverchannel与协程调试热加载Gin的热加载Iris的热加载 常用Golang框架常用…

数据库基础作业(linux系统)

数据库作业 在linux系统下的MySQL 创建数据库 使用数据库 查询当前默认的数据库以及使用的编码方式校验规则 查询创建数据的语句 删除数据库 创建数据表 定义多个字段,用上所有数据类型 mysql> SHOW CREATE TABLE multi_tb; -----------------------------------------…

重新理解z-index

一&#xff0c;前言 今天遇到一个布局兼容问题&#xff0c;调试了一番&#xff0c;发现z-index的表现和自己的认知不相符&#xff0c;才知道自己对z-index的认知有错误&#xff0c;于是写篇文章总结下这个z-index的具体使用。有基础的朋友可以直接看第四节。 二&#xff0c;标…

Android 内存治理之线程

1、 前言 当我们在应用程序中启动一个线程的时候&#xff0c;也是有可能发生OOM错误的。当我们看到以下log的时候&#xff0c;就说明系统分配线程栈失败了。 java.lang.OutOfMemoryError: pthread_create (1040KB stack) failed: Out of memory这种情况可能是两种原因导致的。…

行业追踪,2023-07-06,市场反馈平平

自动复盘 2023-07-06 成交额超过 100 亿 排名靠前&#xff0c;macd柱由绿转红 成交量要大于均线 有必要给每个行业加一个上级的归类&#xff0c;这样更能体现主流方向 rps 有时候比较滞后&#xff0c;但不少是欲杨先抑&#xff0c; 应该持续跟踪&#xff0c;等 macd 反转时参与…

rust 从转移说起

Rust 专门提出了所有权和转移的概念&#xff0c;第一次接触总感觉晦涩&#xff0c;不属于正常思维&#xff0c;但还是得耐下性子&#xff0c;观摩观摩 Rust 所谓的转移。 Rust 中&#xff0c;对大多数类型而言&#xff0c;给变量赋值、给函数传值或者从函数返回值&#xff0c;…

Eclipse显示层级目录结构(像IDEA一样)

有的小伙伴使用IDEA习惯了&#xff0c;可能进入公司里面要求使用eclipse&#xff0c;但是eclipse默认目录是并列显示&#xff0c;而不是层级显示。部分人用起来感觉十分不方便。我们可以更改一下设置。 1、打开eclipse&#xff0c;找到这里 2、选择PackagePresentation 3、选…

支持跨语言、人声狗吠互换,仅利用最近邻的简单语音转换模型有多神奇

AI 语音转换真的越复杂越好吗&#xff1f;本文就提出了一个方法简单但同样强大的语言转换模型&#xff0c;与基线方法相比自然度和清晰度毫不逊色&#xff0c;相似度更是大大提升。 AI 参与的语音世界真神奇&#xff0c;既可以将一个人的语音换成任何其他人的语音&#xff0c;…

express框架中间件

1.介绍 说明&#xff1a;Express框架中间件是指在处理HTTP请求前或后对请求和响应进行处理的函数。具体而言&#xff0c;中间件可以&#xff1a; 执行一些公共的逻辑&#xff0c;比如身份验证、日志记录、错误处理等。修改请求和响应&#xff0c;比如缓存、压缩等。控制请求流…

ModaHub魔搭社区:基于 Amazon EKS 搭建开源向量数据库 Milvus

目录 01 前言 02 架构说明 03 先决条件 04 创建 EKS 集群 05 部署 Milvus 数据库 06 优化 Milvus 配置 07 测试 Milvus 集群 08 总结 01 前言 生成式 AI&#xff08;Generative AI&#xff09;的火爆引发了广泛的关注&#xff0c;也彻底点燃了向量数据库&…

Ubuntu中删除LibreOffice方法

目录 删除LibreOffice套件 删除所有与LibreOffice相关的软件包 删除与LibreOffice相关的配置文件 删除LibreOffice套件 1、打开终端。您可以使用快捷键Ctrl Alt T来打开终端。 2、输入以下命令以卸载LibreOffice套件&#xff1a; sudo apt-get remove libreoffice* 删…

[管理与领导-7]:新任管理第1课:管理转身--从技术业务走向管理 - 管理常识1

目录 第1章 管理基本概念 1.1 什么是管理&#xff1f; 1.2 管理的要素与职能 第2章 管理是什么&#xff1f; 2.1 以终为始 2.2 资源的优化配置 2.3 分而治之&#xff1a;分目标、分任务、分权力、分利益 2.4 目标明确 2.5 优先级 2.6 知人善用&#xff0c;人尽其才 …

【零基础入门学习Python---Python与其他技术的整合之快速入门实践】

&#x1f680; 零基础入门学习Python&#x1f680; &#x1f332; 算法刷题专栏 | 面试必备算法 | 面试高频算法 &#x1f340; &#x1f332; 越难的东西,越要努力坚持&#xff0c;因为它具有很高的价值&#xff0c;算法就是这样✨ &#x1f332; 作者简介&#xff1a;硕风和炜…

2023和鲸夏令营创作活动【黄金价格分析预测】

2023和鲸夏令营创作活动【黄金价格分析预测】 文章目录 2023和鲸夏令营创作活动【黄金价格分析预测】一、项目背景二、数据说明三、数据预处理四、数据探索性分析五、构建LSTM模型预测1、构建LSTM模型2、绘制loss的变化曲线3、进行预测 一、项目背景 本项目的目标是分析并预测…

SpringBoot——在测试阶段验证Web表现层的接口是否正常

验证请求状态 之前我们实现了在测试环境中开启Web环境&#xff0c;并且在测试阶段发送虚拟请求&#xff0c;并看到了返回的结果&#xff0c;这次我们不止要看他的请求结果&#xff0c;还要看他的请求过程和请求状态 匹配请求状态 首先就是查看请求的状态。主要介绍的就是一个…