LeetCode刷题2:链表篇

news2024/9/25 11:17:46

提示:本篇共7道力扣题目供大家食用,时间自行把控~

算法刷题系列笔记

  • LeetCode刷题1:数组篇

文章目录

  • 算法刷题系列笔记
  • 作者有话说
  • 一、链表知识
    • 1.1 什么是链表?
    • 1.2 链表的类型
    • 1.3 链表操作
  • 二、经典题目
    • 2.1 Leetcode203.移除链表元素
    • 2.2 LeetCode707 设计链表
    • 2.3 LeetCode206 反转链表
    • 2.4 LeetCode24 两两交换链表中的节点
    • 2.5 LeetCode19 删除链表的倒数第N个节点
    • 2.6 LeetCode160 链表相交
    • 2.7 LeetCode142 环形链表II
  • 三、推荐题目
  • 总结


作者有话说

  1、本篇是算法刷题系列文章的第 2,写此系列的目的是为了让自己对题目的理解更加深刻。

  2、本系列博客主要参考了卡哥的 代码随想录博客 以及 卡哥本人B站讲解的视频 代码随想录B站视频 ,强烈推荐给大家,因为本人学习中 Python为主,因此博客主要由 Python 代码呈现给大家,需要其他语言的版本,卡哥博客链接自取。


一、链表知识

1.1 什么是链表?

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

  链表在内存中不是连续分布的

1.2 链表的类型

  • 单链表: 只能从前往后进行遍历链表,结构如下图所示:
    单链表
  • 双链表: 每一个节点有两个指针域,一个指向下一个节点,一个指向上一个节点;既可以向前查询也可以向后查询。结构如下图所示:
    双链表
  • 循环链表: 链表首尾相连,结构如下图所示:
    循环链表

1.3 链表操作

  • 删除节点: 删除节点C的操作如下图所示:
    删除操作
  • 添加节点: 添加节点E;这里有三种插入方法:头插(设置虚拟头节点);尾插(先遍历链表找到链表的尾部,然后插入);在某个位置插入(遍历链表找到此位置,然后插入新节点)。添加节点操作如下图所示:

添加节点

二、经典题目

2.1 Leetcode203.移除链表元素

  • 原题地址: 203.移除链表元素
  • 题目描述: 给你一个链表的头节点 head 和一个整数 val ,请你删除链表中所有满足 Node.val == val 的节点,并返回 新的头节点 。
  • 解题思路: 解决此题主要有两步:1、遍历链表找到满足题意的节点;2、删除对应的节点(只需让当前节点的前一个结点指向此节点后面的一个节点,即可达到删除节点的目的)。注意:添加一个虚拟头节点 dummy_head,使得删除头节点和其他节点的规则一致。
  • 代码如下:
class Solution:
    def removeElements(self, head: Optional[ListNode], val: int) -> Optional[ListNode]:
        # 设置虚拟头节点
        dummy_head = ListNode(next=head)
        curNode = dummy_head
        while(curNode.next!=None):
            if(curNode.next.val == val):
                # 找到后,删除cur.next节点
                curNode.next = curNode.next.next 
            else:
            	# 没找到,更新curNode
                curNode = curNode.next
        return dummy_head.next

2.2 LeetCode707 设计链表

  • 原题地址: 707.设计链表
  • 题目描述: 自己设计一个链表,具有以下功能:
  • get(index) 获取链表中第 index 个节点的值;
  • addAtHead(val) 在链表的第一个元素之前添加一个值为 val 的节点;
  • addAtTail(val) 将值为 val 的节点追加到链表的最后一个元素;
  • addAtIndex(index,val) 在链表中的第 index 个节点之前添加值为 val 的节点;
  • deleteAtIndex(index) 如果索引 index 有效,则删除链表中的第 index 个节点。
  • 解题思路:
  • 代码如下: 单链表 + 双链表

单链表:

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

    def __init__(self):
        self._head = Node(0)
        self._count = 0

    def get(self, index: int) -> int:
        if 0 <= index <self._count:
            temp = self._head
            for i in range(index + 1):
                temp = temp.next
            return  temp.val
        else:
            return -1

    def addAtHead(self, val: int) -> None:
        self.addAtIndex(0, val)

    def addAtTail(self, val: int) -> None:
        self.addAtIndex(self._count, val)

    def addAtIndex(self, index: int, val: int) -> None:
        if index < 0:
            index =0
        elif index > self._count:
            return 
        add_node = Node(val)
        curNode = self._head
        while index:
            curNode =  curNode.next
            index -= 1
        else:
            add_node.next, curNode.next = curNode.next, add_node
            # 计数累加
            self._count += 1

    def deleteAtIndex(self, index: int) -> None:

        if 0 <= index < self._count:
            curNode = self._head
            while index:
                curNode = curNode.next
                index -= 1
            curNode.next = curNode.next.next
            self._count -= 1

双链表: 相对于单链表,Node新增了prev属性

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

class MyLinkedList:

    def __init__(self):
    	# 虚拟节点
        self._head, self._tail = Node(0), Node(0)  
        self._head.next, self._tail.prev = self._tail, self._head
        # 添加的节点数
        self._count = 0 

    def _get_node(self, index: int) -> Node:
        # 当index小于_count//2时, 使用_head查找更快, 反之_tail更快
        if index >= self._count // 2:
            # 使用prev往前找
            node = self._tail
            for _ in range(self._count - index):
                node = node.prev
        else:
            # 使用next往后找
            node = self._head   
            for _ in range(index + 1):
                node = node.next
        return node

    def get(self, index: int) -> int:

        if 0 <= index < self._count:
            node = self._get_node(index)
            return node.val
        else:
            return -1

    def addAtHead(self, val: int) -> None:

        self._update(self._head, self._head.next, val)

    def addAtTail(self, val: int) -> None:
    
        self._update(self._tail.prev, self._tail, val)

    def addAtIndex(self, index: int, val: int) -> None:

        if index < 0:
            index = 0
        elif index > self._count:
            return
        node = self._get_node(index)
        self._update(node.prev, node, val)

    def _update(self, prev: Node, next: Node, val: int) -> None:

        # 计数累加
        self._count += 1
        node = Node(val)
        prev.next, next.prev = node, node
        node.prev, node.next = prev, next

    def deleteAtIndex(self, index: int) -> None:

        if 0 <= index < self._count:
            node = self._get_node(index)
            # 计数-1
            self._count -= 1
            node.prev.next, node.next.prev = node.next, node.prev

2.3 LeetCode206 反转链表

  • 原题地址: 206. 反转链表
  • 题目描述: 给你单链表的头节点 head ,请你反转链表,并返回反转后的链表。
  • 解题思路: 双指针法:看图解理解过程
       第1步: 设置两个指针,prevcurprev=None (空指针),cur=head (指向头节点);
       第2步: 设置 temp=cur.next 保存 cur 后面的节点,pre、cur 向后移动;
       第3步: 循环第 2 步,直到 cur=None 时结束,完成链表翻转;
       第4步: 返回 prev,即新链表的头节点。

解题思路图解

  • 代码如下:

法一:双指针

class Solution:
    def reverseList(self, head: Optional[ListNode]) -> Optional[ListNode]:
        cur = head   
        pre = None
        while(cur!=None):
            # 保存一下 cur 的下一个节点
            temp = cur.next 
            cur.next = pre #反转
            #更新pre、cur指针
            pre = cur
            cur = temp
        return pre

法二:递归

class Solution:
    def reverseList(self, head: Optional[ListNode]) -> Optional[ListNode]:

        def reverse(prev, cur):
            if not cur:
                return prev;
            temp = cur.next
            # 翻转操作
            cur.next = prev
            # 下一轮反转操作
            return reverse(cur, temp)
        return reverse(None, head)

2.4 LeetCode24 两两交换链表中的节点

  • 原题地址: 24. 两两交换链表中的节点
  • 题目描述: 给你一个链表,两两交换其中相邻的节点,并返回交换后链表的头节点。你必须在不修改节点内部的值的情况下完成本题(即,只能进行节点交换)。
  • 解题思路: 题目要求不修改节点内部值完成,也就是让我们拿 整个节点 去做交换操作。具体交换见图解。
       第1步: 设置4个指针,dummy_head = ListNode(next=head)、prev、cur、post,prev=dummy_head(指向A节点),cur=prev.next(指向B节点),post=prev.next.next(指向C节点);
       第2步: 根据 cur.next = post.next post.next = cur prev.next = post 更新各个指针;
       第3步: 循环第2步,直到 prev.next == None(偶数节点) and prev.next.next = None(奇数节点)时结束.

图解

  • 代码如下:
class Solution:
    def swapPairs(self, head: Optional[ListNode]) -> Optional[ListNode]:
        dummy_head = ListNode(next=head)
        prev = dummy_head
        
        # 交换
        while prev.next and prev.next.next:
            cur = prev.next
            post = prev.next.next
            
            # prev,cur,post对应最左,中间的,最右边的节点
            cur.next = post.next
            post.next = cur
            prev.next = post

            prev = prev.next.next
        return dummy_head.next

2.5 LeetCode19 删除链表的倒数第N个节点

  • 原题地址: 19.删除链表的倒数第N个节点
  • 题目描述: 给你一个链表,删除链表的 倒数n 个结点,并且返回链表的头结点。
  • 解题思路: 快慢指针法:
       第1步: 定义 fast指针slow指针 ,初始值为虚拟头结点;
       第2步: fast 首先走 n + 1 步 ,为什么是 n+1 呢,因为只有这样同时移动的时候 slow 才能指向删除节点的上一个节点(方便做删除操作);
       第3步: fastslow 同时移动,直到 fast 指向末尾,删除 slow 指向的下一个节点。
  • 代码如下:
class Solution:
    def removeNthFromEnd(self, head: Optional[ListNode], n: int) -> Optional[ListNode]:

        dummy_head = ListNode()
        dummy_head.next = head

        # 第 1 步:初始化
        slow, fast = dummy_head, dummy_head
        # 第 2 步: fast先往前走n步
        while(n!=0): 
            fast = fast.next
            n -= 1
        # 第 3 步: fast 走到结尾后,slow 的下一个节点为倒数第N个节点
        while(fast.next!=None):
            slow = slow.next
            fast = fast.next
        # 删除节点
        slow.next = slow.next.next 
        return dummy_head.next

2.6 LeetCode160 链表相交

  • 原题地址: 160. 链表相交
  • 题目描述: 给你两个单链表的头节点 headAheadB ,请你找出并返回两个单链表相交的起始节点。如果两个链表不存在相交节点,返回 null
  • 解题思路: 根据 快慢法则,走的快的一定会追上走得慢的。在这道题里,有的链表短,他走完了就去走另一条链表,我们可以理解为走的快的指针。那么,只要其中一个链表走完了,就去走另一条链表的路。如果有交点,他们最终一定会在同一个位置相遇。
  • 代码如下:
class Solution:
    def getIntersectionNode(self, headA: ListNode, headB: ListNode) -> ListNode:

        if headA is None or headB is None: 
            return None
        cur_a, cur_b = headA, headB     # 用两个指针代替a和b


        while cur_a != cur_b:
        	# 如果a走完了,那么就切换到b走
            cur_a = cur_a.next if cur_a else headB  
            # 同理,b走完了就切换到a    
            cur_b = cur_b.next if cur_b else headA      

        return cur_a

2.7 LeetCode142 环形链表II

  • 原题地址: 142.环形链表II
  • 题目描述: 给定一个链表的头节点 head ,返回链表开始 入环的第一个节点。 如果链表无环,则返回 null。如果链表中有某个节点,可以通过连续跟踪 next 指针再次到达,则链表中存在环。 为了表示给定链表中的环,评测系统内部使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。如果 pos-1,则在该链表中没有环。注意:pos 不作为参数进行传递,仅仅是为了标识链表的实际情况。 不允许修改链表。
  • 解题思路: 分两步解决:1、判断链表是否环(快慢指针法);2、如果有环,如何找到这个环的入口(两个指针相遇的时候就是 环形入口的节点)。
  • 代码如下:
class Solution:
    def detectCycle(self, head: ListNode) -> ListNode:
        slow, fast = head, head
        while fast and fast.next:
            slow = slow.next
            fast = fast.next.next
            # 如果相遇
            if slow == fast:
                p = head
                q = slow
                while p!=q:
                    p = p.next
                    q = q.next
                return p

        return None

三、推荐题目

  • 92. 反转链表 II
  • 234. 回文链表
  • 83. 删除排序链表中的重复元素
  • 82. 删除排序链表中的重复元素 II
  • 141. 环形链表
  • 1669. 合并两个链表

总结

  链表篇到这里就结束了,若文章中有表述不当的地方还望大家多多指出,哈希表篇见吧。

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

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

相关文章

vue-jest vue3

1. 使用vite搭建测试项目&#xff1a; vue create test-vue-jest 选择单元测试&#xff1a;Unit Testing--->jest 2. 配置 jest.config.js module.exports {transform: {"^.\\.vue$": "vue-jest",},preset: vue/cli-plugin-unit-jest/presets/types…

【关于几个问题的思考】

项目如何部署在服务器上面的 此文章以springboot 项目为例&#xff1a; 1.需要申请一台服务器&#xff0c;安装Linux操作系统 2.在服务器安装jdk ,不需要安装Tomcat&#xff0c;springboot 项目内嵌 Tomcat&#xff1b;安装项目的依赖项&#xff1a;如mysql redis等 3.此处利用…

Oracle SQL执行计划操作(9)——位图相关操作

​​​​​​9. 位图相关操作 该类操作基于位图数据(例如:位图索引的位图数据)进行位操作,或将其他结构数据转成位图数据以利用位操作。根据不同的具体SQL语句及其他相关因素,如下各操作可能会出现于相关SQL语句的执行计划。 1)BITMAP AND 对两个位图索引进行“与”(…

【CLS数据淘金第四期】网络流日志-云联网日志分析

导语 云联网&#xff08;Cloud Connect Network&#xff0c;CCN&#xff09;云联网覆盖全球 20 地域&#xff0c;提供云上私有网络间&#xff08;VPC&#xff09;、VPC 与本地数据中心间&#xff08;IDC&#xff09;内网互联的服务&#xff0c;具备全网多点互联、路由自学习、…

Hypermesh三维网格划分技能,以汽车发动机连杆结构为例

作者&#xff1a;米条老师&#xff0c;仿真秀专栏作者 Hypermesh三维单元的划分功能还是非常的丰富和灵活的&#xff0c;通常掌握主要的几个命令基本就能够满足大部分的网格划分工作。首先我们先了解一下在hypermesh中实现三维网格划分的基本步骤&#xff1a; 几何部件分组及…

finereport开发者需要关注的问题

版本问题 如果使用高版本开发&#xff0c;则无法在低版本的设计使用与发布, 所以第一件事情就是要把设计器的版本弄好。 请使用v10.0.0(本地版本需要与当前的中台版本一致)&#xff0c;目前官方已没有直接下载到v10.0.0完整包的地址了&#xff0c;例如&#xff1a;下图为当前的…

大佬指明方向!使用微服务的最佳实践以及如何避免采用微服务架构可能带来的复杂性陷阱

什么是微服务 微服务应用是与单体应用区分开来的. 当一个单体项目随着业务的发展会越来越膨胀,变得更加难维护,从一开始仅需一两个人到需要两三个团队,多个团队维护同一个项目无疑是一场灾难,沟通成本大大增加,技术协同也会十分困难. 举个例子,我在上一家公司维护过一个后台项…

IP地址虚拟网络与虚拟机网络配置

欢迎关注博主 Mindtechnist 或加入【Linux C/C/Python社区】一起探讨和分享Linux C/C/Python/Shell编程、机器人技术、机器学习、机器视觉、嵌入式AI相关领域的知识和技术。 IP地址虚拟网络与虚拟机网络配置1. IP地址与子网划分☞IP地址☞特殊IP地址☞IP地址申请☞子网掩码☞子…

spider

大家好 我是Yhen 今天给大家分享一下 如何爬取卡塔尔世界杯球员榜 数据来源&#xff1a;百度体育 https://tiyu.baidu.com/match/%E4%B8%96%E7%95%8C%E6%9D%AF/tab/%E7%90%83%E5%91%98%E6%A6%9C/current/0 文章目录一.需求分析二.思路分析三.代码实战四.源码获取一.需求分析…

强强联合 加速科技“牵手”清华大学达成深度战略合作

近日&#xff0c;清华大学集成电路学院成功采购了加速科技ST2500系列高性能数模混合测试机&#xff08;浙江省首台套装备&#xff09;。加速科技“牵手”清华大学&#xff0c;共同推进集成电路自主技术的创新升级&#xff0c;就集成电路学科教学科研、人才培养展开深度合作。 清…

Java Spring后处理器

Java Spring后处理器 在Spring框架中&#xff0c;交给Spring管理的类信息都会被Spring底层自动加载被封装成对应的BeanDefinition对象存储在beanDefinitionMap的Map集合中去&#xff0c;那么除了直接将类信息配置的方式外&#xff0c;还有别的方式可以对想要交给Spring管理的类…

matlab在管理学中的应用简matlab基础【二】

1、MATLAB语言概述 1.1 MATLAB语言的发展 matlab语言是由美国的Clever Moler博士于1980年开发的 MATLAB Matrix Laboratory 它将一个优秀软件的易用性与可靠性、通用性与专业性 、一般目的的应用与高深的科学技术应用有机的结合 MATLAB是一种直译式的高级语言&#xff0c;比…

【安装Ubuntu18.04遇到的问题】未找到WIFI适配器

大家好&#xff0c;我是小政。好久没有更新文章&#xff0c;近期开始陆续分享一些研究生阶段正在学习的知识和遇到的一些问题。 联想拯救者Y9000P关于安装Ubuntu未找到WIFI适配器的解决方法1.Ubuntu18.042.网卡信息3.解决方法&#xff08;1&#xff09;用手机USB连接电脑提供网…

如何判断对象是否该被回收(引用计数法、可达性分析算法)

&#x1f468;‍&#x1f4bb;个人主页&#xff1a; 才疏学浅的木子 &#x1f647;‍♂️ 本人也在学习阶段如若发现问题&#xff0c;请告知非常感谢 &#x1f647;‍♂️ &#x1f4d2; 本文来自专栏&#xff1a; JVM &#x1f308; 算法类型&#xff1a;Hot100题 &#x1f30…

计算机的应用领域

文章目录计算机的应用领域1、商业2、银行业3、保险行业4、教育行业5、市场营销6、卫生保健7、工程设计8、军事9、通讯10、政府计算机的应用领域 本节&#xff0c;我将带领您了解计算机在各个领域的应用。 1、商业 计算机的功能丰富&#xff0c;极高的计算能力&#xff0c;计…

sqli-labs/Less-56

这一关的欢迎界面提示我们还是以id作为注入点 我们仍然有14次尝试机会 首先我们还是先来判断一下是否属于数字型注入 输入如下 id1 and 12 回显如下 正确回显 属于字符型 接着输入1 查看回显 这个回显说明两件事情 一个是我们后面不能使用报错注入进行注入了 一个是我们这个…

Elasticsearch:使用反向地理编码在地图上显示自定义区域统计数据

在实际的许多应用中&#xff0c;我们可能并不一定按照行政区来进行划分区域&#xff0c;比如我们常说江浙一代&#xff0c;我们可以理解江苏和浙江这两个省合在一起&#xff0c;而不是把它们分开。我们有时也说长江三角区&#xff0c;它可能是跨几个省市的一个区域&#xff0c;…

每隔一段时间自动敲键盘的的vbs脚本

1. 上代码 set wscreateobject("wscript.shell") do ws.sendkeys "{TAB}" WScript.Sleep Int(6 *Rnd1)*1000 loop2. 代码解释 每隔1~6秒,按一次TAB键 2.1 循环执行操作代码 do ....操作..... loop2.2 按下Tab键 ws.sendkeys "{TAB}" 即…

HTML5期末大作业商城网页设计与实:(手表 3页)HTML+CSS

⛵ 源码获取 文末联系 ✈ Web前端开发技术 描述 网页设计题材&#xff0c;DIVCSS 布局制作,HTMLCSS网页设计期末课程大作业 | 在线商城购物 | 水果商城 | 商城系统建设 | 多平台移动商城 | H5微商城购物商城项目 | HTML期末大学生网页设计作业 HTML&#xff1a;结构 CSS&#…

python中字典的循环遍历的方式

python开发中经常会用到对于字典、列表等数据的循环遍历&#xff0c;但是python中对于字典的遍历对于很多初学者来讲非常陌生&#xff0c;今天就来讲一下python中字典的循环遍历的两种方式。 注意&#xff1a; python2和python3中&#xff0c;下面两种方法都是通用的。 1、只…