二刷力扣--链表

news2024/10/6 20:39:02

链表

链表类型:
单链表(可以访问后面的一个节点)
双链表(可以访问前后节点)
循环链表(最后一个节点指向首节点)

在Python中定义单链表节点:

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

移除链表元素 203.

#链表删除 #哑节点
给你一个链表的头节点 head 和一个整数 val ,请你删除链表中所有满足 Node.val == val 的节点,并返回 新的头节点

为了统一处理删除操作,在head节点前添加一个哑节点

class Solution:
    def removeElements(self, head: Optional[ListNode], val: int) -> Optional[ListNode]:
        dummy = ListNode(0, head)
        pre = dummy
        cur = dummy.next
        while cur:
            if cur.val == val:
                pre.next = cur.next 
                cur = cur.next
            else:
                pre = pre.next
                cur = cur.next
        
        return dummy.next

Python有垃圾回收,不需要手动删除节点。

设计链表 707.

你可以选择使用单链表或者双链表,设计并实现自己的链表。

单链表中的节点应该具备两个属性:valnextval 是当前节点的值,next 是指向下一个节点的指针/引用。

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

class MyLinkedList:
    def __init__(self):
        self.dummy = Node(-1, None)
        self.max_index = -1  

    def get(self, index: int) -> int:
        if index < 0 or index > self.max_index:
            return -1
        cur = self.dummy.next 
        for  i in range(index):
            cur = cur.next
        return cur.val

    def addAtHead(self, val: int) -> None:
        self.dummy.next  = Node(val, self.dummy.next)
        self.max_index += 1

    def addAtTail(self, val: int) -> None:
        cur = self.dummy
        while cur.next:
            cur = cur.next
        cur.next = Node(val)
        self.max_index += 1

    def addAtIndex(self, index: int, val: int) -> None:
        if  index < 0 or index > self.max_index + 1:
            return 
        cur = self.dummy
        i = 0
        for i in range(index):
            cur = cur.next

        cur.next = Node(val, cur.next)
        self.max_index += 1

    def deleteAtIndex(self, index: int) -> None:
        if  index < 0 or index > self.max_index:
            return 
        cur = self.dummy
        for i in range(index):
            cur = cur.next

        cur.next = cur.next.next 
        self.max_index -= 1

反转链表 206.

给你单链表的头节点 head ,请你反转链表,并返回反转后的链表。
#双指针

使用temp保存cur.next ,因为反转后cur.next就改变了,无法再访问原来的下一个元素了。

class Solution:
    def reverseList(self, head: Optional[ListNode]) -> Optional[ListNode]:
      pre = None
      cur = head
      while cur:
        temp = cur.next # 下一个节点
        cur.next  = pre # 反转next方向

        pre = cur
        cur = temp # 去下一个
      
      return pre 

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

#哑节点
给你一个链表,两两交换其中相邻的节点,并返回交换后链表的头节点。你必须在不修改节点内部的值的情况下完成本题(即,只能进行节点交换)。

有些题解里很多cur.next.next.next,看起来很麻烦。 用临时节点记录一下似乎就不用那么多next了。而且也不用考虑.next赋值的顺序了。

class Solution:
    def swapPairs(self, head: Optional[ListNode]) -> Optional[ListNode]:
        dummy = ListNode(0, head)
        cur = dummy
        # 交换cur后面的两个节点
        while cur.next and cur.next.next:
            node1 = cur.next        
            node2 = node1.next  
            node3 = node2.next  
            #  cur->node1->node2-->node3(node2.next)  ----> cur->node2->node1-->node3(node2.next)  
            cur.next = node2  
            node2.next = node1 
            node1.next = node3
           
            cur = node1 
        
        return dummy.next

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

#双指针 #哑节点
双指针的应用。快指针fast先走n步,当快指针到达倒数第1个节点时,慢指针slow到达倒数n+1个节点,删除slow的下一个节点。
哑节点对简化删除操作很有用,如果不用哑节点,删除head就要特殊处理。

class Solution:
    def removeNthFromEnd(self, head: Optional[ListNode], n: int) -> Optional[ListNode]:
        dummy = ListNode(0, head)
        fast = dummy
        slow = dummy
        # 当fast 到达倒数第1个节点, slow到达倒数第n+1个节点
        for i in range(n):
            fast = fast.next
        while fast.next :
            fast = fast.next
            slow = slow.next
        slow.next = slow.next.next 
        return dummy.next 

链表相交 面试题 02.07. 同 160

#双指针
给你两个单链表的头节点 headAheadB ,请你找出并返回两个单链表相交的起始节点。如果两个链表没有交点,返回 null

两个链表如果有相同的节点,则从相同节点开始,一直到末尾都是相同的。
让较长的链表先走 abs(lengthA-lengthB)个节点,然后比较两个链表。

class Solution:
    def getIntersectionNode(self, headA: ListNode, headB: ListNode) -> ListNode:
        def getLength(head):
            length = 0
            while head:
                head = head.next
                length += 1
            return length
        lengthA = getLength(headA)
        lengthB = getLength(headB) 
        Long, Short = (headA, headB) if lengthA > lengthB  else (headB, headA)

        for _ in range (abs(lengthA- lengthB)):
            Long = Long.next
        while Short:
            if Short == Long:
                return Short
            else:
                Short = Short.next
                Long = Long.next
        return None
      

环形链表II 142.

#集合 #双指针

  1. 直接用set记录访问过的节点,再次遇到则表明出现了环。
class Solution:
    def detectCycle(self, head: Optional[ListNode]) -> Optional[ListNode]:
        visited = set()
        pos = head
        while pos:
            if  pos in visited:
                return pos
            else:
                visited.add(pos)
            pos = pos.next
        return None
  1. 双指针。快指针fast一次走两步,慢指针slow一次走一步。如果有环,两个指针一定会遇到。
    而找到环的入口比较难,需要推导一下。(这个不太好理解,推荐看代码随想录的视频)
    请添加图片描述

相遇时,slow指针走过的节点数是 x+y, fast走过的节点数是 x+y+ n(y+z) ,n>=1
fast一次走两个节点,所以走过的节点数是slow的两倍,即 x+y+n(y+z) = 2(x+y)。 化简一下,得到 x = (n-1)(y+z) + z
n = 1时, x = z 也就是说,一个指针index1从slow与fast相遇点出发,一个指针index2从头节点出发,会在入口节点相遇。

n大于1时和n为1的时候 效果是一样的,一样可以通过这个方法找到 环形的入口节点,只不过,index1 指针在环里 多转了(n-1)圈,然后再遇到index2,相遇点依然是环形的入口节点

class Solution:
    def detectCycle(self, head: Optional[ListNode]) -> Optional[ListNode]:
        fast = head
        slow = head
        while fast and fast.next:
            slow = slow.next
            fast = fast.next.next

            if slow == fast:
                index1 = fast
                index2 = head
                while index1 != index2:
                    index1 = index1.next
                    index2 = index2.next
                return index2
        
        return None

链表小结

哑节点对简化链表操作很有用。添加一个哑节点,对头节点的处理会和其他节点一样。
双指针是常用的方法,可以用来判断链表是否有环,找到链表倒数第n个元素。

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

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

相关文章

TypeScript泛型

什么是泛型&#xff1f; "泛"就是广泛的意思&#xff0c;"型"就是数据类型。顾名思义&#xff0c;泛型就是适用于多种数据类型的一种类型。 泛型的作用 它能够帮助我们构建出复用性更强的代码 function getResult(value: number): number {return value…

高效办公必备,批量重命名与翻译一气呵成

在电脑使用中&#xff0c;我们常常需要批量修改文件名或对文件进行翻译。这时候&#xff0c;有一个得力的工具可以助你一臂之力&#xff0c;那就是“固乔文件管家”。下面就教你如何使用这个软件&#xff0c;轻松完成批量重命名和翻译大量文件的操作。 首先&#xff0c;你需要下…

基于 Alpine 环境构建 aspnetcore6-runtime 的 Docker 镜像

关于 Alpine Linux 此处就不再过多讲述&#xff0c;请自行查看相关文档。 .NET 支持的体系结构 下表列出了当前支持的 .NET 体系结构以及支持它们的 Alpine 版本。 这些版本在 .NET 到达支持终止日期或 Alpine 的体系结构受支持之前仍受支持。请注意&#xff0c;Microsoft 仅正…

mysql技术文档--之与redo log(重做日志)庖丁解析-超级探索!!!

阿丹&#xff1a; 在刚开始写本文章的是还不太清楚要如何去细啃下这两个体系&#xff0c;在查阅资料的过程中。发现大厂阿里的庖丁解InnoDB系列&#xff0c;详细了的写了很多底层知识&#xff0c;于是基于这个这两个文章才有了阿丹的这篇文章。 整体认知&#xff1a; 在 MySQ…

数据结构——排序算法——插入排序

交换法插入排序 void swap(vector<int> arr, int i, int j) {int temp arr[i];arr[i] arr[j];arr[j] temp;}void insertSort(vector<int> arr) {// 从第二个数开始&#xff0c;往前插入数字for (int i 1; i < arr.size(); i) {// j 记录当前数字下标int j …

骨传导耳机的危害有哪些?会损害听力吗?

如果正常的使用&#xff0c;骨传导耳机是没有危害的&#xff0c;由于骨传导耳机独特的传声方式&#xff0c;所以并不会对人体造成损伤&#xff0c;还可以在一定程度上保护听力。 如果想更具体知道骨传导耳机有什么危害&#xff0c;就要先了解什么是骨传导耳机&#xff0c;骨传…

虚拟机Ubuntu操作系统常用终端命令(1)(详细解释+详细演示)

虚拟机Ubuntu操作系统常用终端命令 本篇讲述了Ubuntu操作系统常用的三个功能&#xff0c;即归档&#xff0c;软链接和用户管理方面的相关知识。希望能够得到大家的支持。 文章目录 虚拟机Ubuntu操作系统常用终端命令二、使用步骤1.归档1.1创建档案包1.2还原档案包1.3归档并压缩…

〔022〕Stable Diffusion 之 生成视频 篇

✨ 目录 &#x1f388; 视频转换 / mov2mov&#x1f388; 视频转换前奏准备&#x1f388; 视频转换 mov2mov 使用&#x1f388; 视频转换 mov2mov 效果预览&#x1f388; 视频无限缩放 / Infinite Zoom&#x1f388; 视频无限缩放 Infinite Zoom 使用 &#x1f388; 视频转换 /…

ACL(访问控制列表)

文章目录 一、ACL定义常见功能 二、基于ACL的包过滤定义包过滤的方向包过滤的工作流程注意事项 三、ACL分类四、常用命令 首先可以看下思维导图&#xff0c;以便更好的理解接下来的内容。 一、ACL 定义 ACL&#xff0c;也称为访问控制列表&#xff0c;是一种网络安全工具&…

8个免费的AI和LLM游乐场

推荐&#xff1a;使用 NSDT场景编辑器 快速搭建3D应用场景 在本文中&#xff0c;我们的目标是通过引入八个用户友好的平台来弥合这一差距&#xff0c;这些平台使任何人都可以免费测试和比较开源AI模型。此外&#xff0c;它们还提供多种更新型号&#xff0c;确保您及时了解最新进…

浅谈前后端分离的网络拓扑

前后端分离大体分为两种拓扑结构&#xff0c;前端和后端通过开放对外端口的拓扑结构和只有前端开放端口的拓扑结构 前端和后端通过开放对外端口的拓扑结构 比如说前端通过 80 端口对外提供服务&#xff0c;后端通过 8080 端口对外提供服务&#xff0c;前端和后端搭建在同一台服…

sqlserver2012 完全卸载

使用工具 我用的是64位的 双击打开 等待处理完成 输入sql 查询&#xff0c;对查询出来的程序选择批处理&#xff0c;进行批处理卸载 等待卸载完成&#xff0c;期间可能 需要多次点击确认

java授权码方案 软件实现时间授权 离线授权 夏末版

java项目在离线状态下部署到客户端,很容易被反编译,授权容易被破解, 给项目盈利带来很大的困难, 特别是小项目很容易失败, 小项目特别需要完善可靠的授权加密解决方案 本方案只需要集成一个jar包就可以实现在关键节点完成,授权验证,离线时间验证等功能,特别是个中小项目的开发…

解决three.js中加载纹理贴图时,初次渲染不显示的问题

效果&#xff1a; 解决方法&#xff1a;主要是将一些构建网格对象的操作放在了textureLoader.load()方法中&#xff0c;加载图片也用了require init() {// 1, 创建场景对象this.scene new this.$three.Scene();// 2, 创建立方缓冲几何体this.geometry new this.$three.BoxGe…

抖店产品曝光率低怎么解决?提高曝光、点击、转化的技巧,可收藏

我是王路飞。 我之前一直在强调&#xff0c;抖店的核心有且只有一个&#xff0c;就是选品。 店铺内的所有问题&#xff0c;都是产品的问题&#xff0c;而你的运营手段&#xff0c;黑科技等等&#xff0c;终究只是外力罢了&#xff0c;既没办法让你赚到钱&#xff0c;也对你个…

59从零开始学Java之StringBuilder与StringBuffer

作者&#xff1a;孙玉昌&#xff0c;昵称【一一哥】&#xff0c;另外【壹壹哥】也是我哦 千锋教育高级教研员、CSDN博客专家、万粉博主、阿里云专家博主、掘金优质作者 前言 最近的这几篇文章&#xff0c;壹哥一直在给大家讲解字符串相关的内容。其实字符串按照可变性&#xf…

Linux内核分析与应用8-文件系统

本系列是对 陈莉君 老师 Linux 内核分析与应用[1] 的学习与记录。讲的非常之好&#xff0c;推荐观看 留此记录&#xff0c;蜻蜓点水,可作抛砖引玉 8.1 虚拟文件系统的引入 Linux文件系统中最重要的一个概念: 索引节点 Inode 文件系统是具体到分区的,所以不同分区格式化时,可以是…

Seata在Liunx环境启动配置指定JVM大小

Seata从官网下载下来默认分配的内存为2048MB,测试环境因为部署的程序比较多&#xff0c;给Seata分配2048MB内存也显得很奢侈于是在程序启动的时候配置Seata的内存 bin目录下面一个有四个脚本 在Liunx启动Seata我们需要在seata-setup.sh设置JVM seata-setup.sh设置JVM参考Liu…

DT Paint Effects工具(二)

混合笔刷 Paint Effects面板 画布菜单 笔刷和分辨率 高级笔划节点 最小-最大剪裁 笔刷类型 控制通道 笔刷轮廓 必须的物体上用 扭曲 网格设置和网格环境 刺 着色属性 照明Paint Effects 阴影 辉光

考研英语笔记:日本色情业的冰山一角

微信里很多考友说自己撑不住了&#xff0c;是的&#xff0c;这确实是考研过程中&#xff0c;最难熬的一段时光。 这就如&#xff0c;在狭窄的隧道中&#xff0c;前面只有一丝光亮。而后面&#xff0c;漆黑一片&#xff0c;早已没有了退路。 放弃是不可能了。但想拼却又觉得就那…