链表经典题目(力扣 easy)

article/2025/8/20 10:13:20

 全部题目来自力扣,这里只做学习的记录,内容中部分为AI生成,有不对的地方可以评论或者私信哦~~

203. 移除链表元素

(版本一)虚拟头节点法
# 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_headwhile current.next:if current.next.val == val:current.next = current.next.nextelse:current = current.nextreturn dummy_head.next

707. 设计链表

(版本一)单链表法
class ListNode:def __init__(self, val=0, next=None):self.val = valself.next = nextclass MyLinkedList:def __init__(self):self.dummy_head = ListNode()self.size = 0def get(self, index: int) -> int:if index < 0 or index >= self.size:return -1current = self.dummy_head.nextfor i in range(index):current = current.nextreturn current.valdef addAtHead(self, val: int) -> None:self.dummy_head.next = ListNode(val, self.dummy_head.next)self.size += 1def addAtTail(self, val: int) -> None:current = self.dummy_headwhile current.next:current = current.nextcurrent.next = ListNode(val)self.size += 1def addAtIndex(self, index: int, val: int) -> None:if index < 0 or index > self.size:returncurrent = self.dummy_headfor i in range(index):current = current.nextcurrent.next = ListNode(val, current.next)self.size += 1def deleteAtIndex(self, index: int) -> None:if index < 0 or index >= self.size:returncurrent = self.dummy_headfor i in range(index):current = current.nextcurrent.next = current.next.nextself.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)

(版本二)双链表法
class ListNode:def __init__(self, val=0, prev=None, next=None):self.val = valself.prev = prevself.next = nextclass MyLinkedList:def __init__(self):self.head = Noneself.tail = Noneself.size = 0def get(self, index: int) -> int:if index < 0 or index >= self.size:return -1if index < self.size // 2:current = self.headfor i in range(index):current = current.nextelse:current = self.tailfor i in range(self.size - index - 1):current = current.prevreturn current.valdef addAtHead(self, val: int) -> None:new_node = ListNode(val, None, self.head)if self.head:self.head.prev = new_nodeelse:self.tail = new_nodeself.head = new_nodeself.size += 1def addAtTail(self, val: int) -> None:new_node = ListNode(val, self.tail, None)if self.tail:self.tail.next = new_nodeelse:self.head = new_nodeself.tail = new_nodeself.size += 1def addAtIndex(self, index: int, val: int) -> None:if index < 0 or index > self.size:returnif index == 0:self.addAtHead(val)elif index == self.size:self.addAtTail(val)else:if index < self.size // 2:current = self.headfor i in range(index - 1):current = current.nextelse:current = self.tailfor i in range(self.size - index):current = current.prevnew_node = ListNode(val, current, current.next)current.next.prev = new_nodecurrent.next = new_nodeself.size += 1def deleteAtIndex(self, index: int) -> None:if index < 0 or index >= self.size:returnif index == 0:self.head = self.head.nextif self.head:self.head.prev = Noneelse:self.tail = Noneelif index == self.size - 1:self.tail = self.tail.previf self.tail:self.tail.next = Noneelse:self.head = Noneelse:if index < self.size // 2:current = self.headfor i in range(index):current = current.nextelse:current = self.tailfor i in range(self.size - index - 1):current = current.prevcurrent.prev.next = current.nextcurrent.next.prev = current.prevself.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. 反转链表

#(版本一)双指针法
class Solution:def reverseList(self, head: ListNode) -> ListNode:cur = head   pre = Nonewhile cur:temp = cur.next # 保存一下 cur的下一个节点,因为接下来要改变cur->nextcur.next = pre #反转#更新pre、cur指针pre = curcur = tempreturn pre
#(版本二)递归法
class Solution:def reverseList(self, head: ListNode) -> ListNode:return self.reverse(head, None)def reverse(self, cur: ListNode, pre: ListNode) -> ListNode:if cur == None:return pretemp = cur.nextcur.next = prereturn self.reverse(temp, cur)

 234. 回文链表

算法思路

  1. 核心思想

    • 找到链表的中间节点。
    • 反转链表的后半部分。
    • 比较链表的前半部分和反转后的后半部分,如果值完全一致,则是回文链表。
  2. 具体步骤

    • 使用快慢指针找到链表的中间节点(middleNode 方法)。
    • 反转链表的后半部分(reverseList 方法)。
    • 比较链表的前半部分和反转后的后半部分,如果所有节点的值都相等,则返回 True,否则返回 False
  3. 关键点

    • 快慢指针找到中间节点的时间复杂度为 O(n)
    • 反转链表的时间复杂度为 O(n)
    • 比较链表的时间复杂度为 O(n)
    • 总时间复杂度为 O(n),空间复杂度为 O(1)
class ListNode:def __init__(self, x):self.val = x  # 初始化节点的值self.next = None  # 初始化节点的下一个节点为 Noneclass Solution:# 876. 链表的中间结点def middleNode(self, head):slow = fast = head  # 初始化慢指针和快指针,都指向链表头节点while fast and fast.next:  # 当快指针及其下一个节点不为空时slow = slow.next  # 慢指针每次移动一步fast = fast.next.next  # 快指针每次移动两步return slow  # 返回慢指针指向的节点(即链表的中间节点)# 206. 反转链表def reverseList(self, head):pre, cur = None, head  # 初始化前驱节点为 None,当前节点为链表头节点while cur:  # 当当前节点不为空时nxt = cur.next  # 保存当前节点的下一个节点cur.next = pre  # 将当前节点的 next 指向前驱节点pre = cur  # 前驱节点移动到当前节点cur = nxt  # 当前节点移动到下一个节点return pre  # 返回反转后的链表头节点def isPalindrome(self, head):mid = self.middleNode(head)  # 找到链表的中间节点head2 = self.reverseList(mid)  # 反转后半部分链表while head2:  # 遍历反转后的后半部分链表if head.val != head2.val:  # 如果前半部分和后半部分的节点值不相等return False  # 不是回文链表,返回 Falsehead = head.next  # 移动前半部分的指针head2 = head2.next  # 移动后半部分的指针return True  # 所有节点值都相等,是回文链表,返回 True

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

# 递归版本class Solution:def swapPairs(self, head: Optional[ListNode]) -> Optional[ListNode]:if head is None or head.next is None:return head# 待翻转的两个node分别是pre和curpre = headcur = head.nextnext = head.next.nextcur.next = pre  # 交换pre.next = self.swapPairs(next) # 将以next为head的后续链表两两交换return cur

代码执行示例

假设链表为:1 -> 2 -> 3 -> 4 -> None

执行过程:

  1. 第一次递归调用:
    • pre = 1cur = 2next = 3
    • 交换 precur2 -> 1
    • 递归处理 next = 3,得到交换后的链表 4 -> 3
    • pre.next(即 1.next)指向 4 -> 3,最终链表为 2 -> 1 -> 4 -> 3 -> None
    • 返回 cur = 2,即交换后的新链表头节点。

最终链表为:2 -> 1 -> 4 -> 3 -> None

# Definition for singly-linked list.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.nextcurrent.next = current.next.nextcurrent.next.next = temptemp.next = temp1current = current.next.nextreturn dummy_head.next

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

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.nextfast = fast.next# 通过更新第 (n-1) 个节点的 next 指针删除第 n 个节点slow.next = slow.next.nextreturn dummy_head.next

141. 环形链表

方法一

  • 核心思想

    • 使用一个集合 seen 来记录已经访问过的节点。
    • 遍历链表,如果当前节点已经存在于集合中,说明链表存在环;否则,将当前节点添加到集合中,继续遍历。
    • 如果遍历结束(head 为 None),说明链表没有环。
  • 时间复杂度

    • 最坏情况下需要遍历整个链表,时间复杂度为 O(n),其中 n 是链表的节点数。
  • 空间复杂度

    • 使用了一个集合 seen 来存储节点,空间复杂度为 O(n)
# Definition for singly-linked list.
# class ListNode(object):
#     def __init__(self, x):
#         self.val = x
#         self.next = Noneclass Solution(object):def hasCycle(self, head):""":type head: ListNode:rtype: bool"""seen = set()while head:if head in seen:return Trueseen.add(head)head = head.nextreturn False

方法二

  • 快慢指针的核心思想

    • 快指针每次移动两步,慢指针每次移动一步。
    • 如果链表存在环,快指针最终会追上慢指针(相遇)。
    • 如果链表不存在环,快指针会先到达链表末尾。
  • 时间复杂度O(n)

  • 空间复杂度O(1)

def hasCycle(self, head):slow = fast = head  # 初始化慢指针和快指针,都指向链表头节点while fast and fast.next:  # 当快指针及其下一个节点不为空时slow = slow.next  # 慢指针每次移动一步fast = fast.next.next  # 快指针每次移动两步if slow == fast:  # 如果快慢指针相遇return True  # 说明链表存在环return False  # 遍历结束,没有发现环

142. 环形链表 II

快慢指针法

  • 核心思想

    1. 快慢指针
      • 使用快慢指针(fast 和 slow)遍历链表。
      • 快指针每次移动两步,慢指针每次移动一步。
      • 如果链表存在环,快指针最终会追上慢指针(相遇)。
    2. 找到环的入口
      • 当快慢指针相遇时,初始化一个新指针 ptr,指向链表头节点。
      • 同时移动 ptr 和 slow,每次移动一步,直到它们相遇。
      • 相遇的节点就是环的入口节点。
  • 时间复杂度

    • 最坏情况下需要遍历整个链表,时间复杂度为 O(n),其中 n 是链表的节点数。
  • 空间复杂度

    • 只使用了常数级别的额外空间,空间复杂度为 O(1)
class Solution:def detectCycle(self, head):slow = fast = head  # 初始化慢指针和快指针,都指向链表头节点while fast is not None:  # 当快指针不为空时slow = slow.next  # 慢指针每次移动一步if fast.next is None:  # 如果快指针的下一个节点为空return None  # 说明链表没有环,返回 Nonefast = fast.next.next  # 快指针每次移动两步if fast == slow:  # 如果快慢指针相遇ptr = head  # 初始化一个新指针,指向链表头节点while ptr != slow:  # 当新指针和慢指针不相遇时ptr = ptr.next  # 新指针每次移动一步slow = slow.next  # 慢指针每次移动一步return ptr  # 返回新指针指向的节点(即环的入口节点)return None  # 遍历结束,没有发现环,返回 None

21. 合并两个有序链表

1. 算法思路

这段代码的核心思想是 合并两个有序链表。具体步骤如下:

  1. 初始化哨兵节点

    • 创建一个哨兵节点 dummy,用于简化链表操作,避免处理头节点的特殊情况。
    • 使用指针 cur 指向 dummy,用于构建新的链表。
  2. 遍历两个链表

    • 使用 while l1 and l2 循环遍历两个链表,比较当前节点的值:
      • 如果 l1.val < l2.val,将 l1 节点连接到 cur 的后面,并移动 l1 指针。
      • 否则,将 l2 节点连接到 cur 的后面,并移动 l2 指针。
    • 每次连接一个节点后,移动 cur 指针到新连接的节点。
  3. 处理剩余部分

    • 当其中一个链表遍历完毕后,将另一个链表的剩余部分直接连接到 cur 的后面。
  4. 返回结果

    • 返回 dummy.next,即合并后的链表的头节点。

2. 时间复杂度

  • 最坏情况
    • 需要遍历两个链表的全部节点,假设两个链表的长度分别为 m 和 n,则时间复杂度为 O(m + n)
  • 最好情况
    • 如果其中一个链表为空,直接返回另一个链表,时间复杂度为 O(1)

3. 空间复杂度

  • 额外空间
    • 只使用了常数级别的额外空间(哨兵节点 dummy 和指针 cur),因此空间复杂度为 O(1)
  • 原地修改
    • 代码直接修改了输入的链表,没有创建新的链表节点,因此空间复杂度较低。
class Solution:def mergeTwoLists(self, l1, l2):dummy = ListNode(0)  # 哨兵节点cur = dummywhile l1 and l2:if l1.val < l2.val:cur.next = l1l1 = l1.nextelse:cur.next = l2l2 = l2.nextcur = cur.nextcur.next = l1 if l1 else l2  # 将剩余部分连接到结果链表return dummy.next


http://www.hkcw.cn/article/BoHYpKgYGC.shtml

相关文章

UFSH2024 程序化生成 笔记

这篇只是把里面涉及到的网站连接做个记录。有些网站“藏"得太深了。找了半天才找到相关连接 官方视频&#xff1a; [UFSH2024]关于程序化生成&#xff0c;我们还能做什么&#xff1f; | 周杰 徐凯鸣 腾讯IEG Global_哔哩哔哩_bilibili 官方案例资源连接&#xff1a; Vit…

openEuler安装MySql8(tar包模式)

操作系统版本&#xff1a; openEuler release 22.03 (LTS-SP4) MySql版本&#xff1a; 下载地址&#xff1a; https://dev.mysql.com/downloads/mysql/ 准备安装&#xff1a; 上传安装包&#xff1a; 把下载下来的安装包上传到服务器&#xff1a;/opt/software/mysql目录…

JSON Schema

1.JSON Schema的含义 JSON Schema 是用于验证 JSON 数据结构的强大工具&#xff0c;Schema可以理解为模式或者规则&#xff0c;可以理解为JSON中的正则表达式 2.语法 2.1 type 作用&#xff1a;约束数据类型 取值范围&#xff1a;integer&#xff0c;string&#xff0c;object&…

替代 WPS 的新思路?快速将 Word 转为图片 PDF

在这个数字化办公日益普及的时代&#xff0c;越来越多的人开始关注文档处理工具的功能与体验。当我们习惯了某些便捷操作时&#xff0c;却发现一些常用功能正逐渐变为付费项目——比如 WPS 中的一项实用功能也开始收费了。 这款工具最特别的地方在于&#xff0c;可以直接把 W…

华为OD机试真题——Boss的收入(分销网络提成计算)(2025A卷:100分)Java/python/JavaScript/C/C++/GO最佳实现

2025 A卷 100分 题型 本专栏内全部题目均提供Java、python、JavaScript、C、C++、GO六种语言的最佳实现方式; 并且每种语言均涵盖详细的问题分析、解题思路、代码实现、代码详解、3个测试用例以及综合分析; 本文收录于专栏:《2025华为OD真题目录+全流程解析+备考攻略+经验分…

中国批准修建最昂贵运河为何受关注 重塑交通格局引发国际热议

中国即将启动一项震惊全球的大工程——浙赣粤运河。该项目总投资3200亿元,刷新了中国运河造价纪录。这条运河北起浙江杭州,穿过江西,南至广东广州的珠江出海口,全长1237公里,其中江西境内占759公里。通过钱塘江、兰江等水系连接杭州,形成贯穿浙赣粤三省的水上通道。从交通…

广东河源24小时内连震两次 市民难眠

广东河源24小时内连震两次 市民难眠!中国地震台网正式测定,5月30日2时21分在广东河源市源城区发生3.0级地震,震源深度10公里,震中位于北纬23.72度,东经114.68度。此次地震震中5公里范围内平均海拔约52米。震中周边200公里内近5年来共发生3.0级以上地震15次,最大地震是202…

74.用户编辑功能在多次修复后仍未成功实现

在用户编辑功能在多次修复后仍未成功实现之后决定换种方法 对于后端则不需要过多修改&#xff0c;只需要修改前端即可 首先&#xff0c;在 data() 中添加新的状态&#xff1a; 用户模板部分可继续沿用之前的方法所留下来的代码 修改start、cancel、save方法 修改现有的 rege…

Void:免费且隐私友好的 AI 编码利器,挑战 Cursor 地位?

开发者圈儿里最近有点小激动&#xff0c;大家都在议论一个叫Void的开源AI代码编辑器。这家伙在GitHub上人气飙涨&#xff0c;短时间内就斩获了超过22.1k的星标&#xff0c;简直成了科技圈的新宠。它被誉为“黑马”&#xff0c;不仅因为它继承了大家都很熟悉的Visual Studio Cod…

Cadence Innvous导出GDS没有STDCELL/IO/NET/VIA问题的解决方法

Cadence Innvous导出GDS之后&#xff0c;可以重新导入Cadence Virtuoso进行查看。 1. Innovus设计完成后的GDS导出命令 导出gds命令&#xff1a; streamOut [-help] <fileName> [-attachNetProp <string>] [-dieAreaAsBoundary] [-libName <string>] [-map…

菲总统任命新国家警察总长 曾主导前总统逮捕行动

菲律宾总统马科斯选定国家警察刑事调查组组长尼古拉斯托雷出任国家警察新任总长。托雷此前主导了逮捕前总统杜特尔特的行动。菲总统执行秘书卢卡斯贝尔萨敏在马拉卡南宫记者会上宣布了这一任命。交接仪式定于6月2日举行,托雷将接替即将退休的现任总长罗梅尔马比尔。托雷成为马…

《深度搜索-R1-0528》

深度搜索-R1-0528 Paper Link &#xff08;纸质链接&#xff09;&#x1f441;️ 1. 引言 DeepSeek R1 模型进行了小版本升级&#xff0c;当前版本为 DeepSeek-R1-0528。在最新的更新中&#xff0c;DeepSeek R1 通过利用增加的计算资源并在后训练期间引入算法优化机制&#x…

男子翻女友手机才发现小丑竟是自己 女子:我们就是牌友

河南许昌,刘先生称和女友恋爱2年多,女友比自己大5岁带三个娃,相处期间两人很和睦,自己给对方还房贷,孩子都叫自己爸爸了,却意外发现她手机里还有男朋友,备注叫大哥。女方:我和刘先生就是牌友,和手机里男友的马上要结婚了,给的钱全是打牌的钱...随后,女方正牌男友来到…

Arduino 编码器

旋转编码器模块 这次我们将使用的旋转编码器为360度KY-040模块&#xff0c;工作电压: 5V&#xff0c;一圈脉冲数: 20&#xff0c;旋转编码器可通过旋转可以计数正方向和反方向转动过程中输出脉冲的次数&#xff0c;旋转计数和电位计不一样&#xff0c;这种转动计数是没有限制的…

ppt一键制作:ai自动生成PPT,便捷高效超级精美!

深夜的台灯下&#xff0c;你对着杂乱的 PPT 内容反复刷新灵感&#xff0c;鼠标在字体、配色选项间来回穿梭&#xff0c;好不容易拼凑出的页面&#xff0c;却总透着浓浓的 “廉价感”&#xff1b;汇报在即&#xff0c;逻辑混乱的大纲改了又改&#xff0c;每一页感觉合适又不搭&a…

俞敏洪骑车摔倒深夜发博:感谢关心,皮外伤

5月29日,俞敏洪在青海骑行时不慎摔倒,膝盖等处磕破出血。30日凌晨1点多,他发博报平安:29日骑车有点睡着了摔了一下,感谢广大朋友关心,皮外伤,不用担心。责任编辑:zx0002

R语言在生物群落数据统计分析与绘图中的实践应用

随着生物信息学的快速发展&#xff0c;R语言因其开源、自由、免费的特点&#xff0c;在生物群落数据分析领域得到了广泛应用。生物群落数据多样且复杂&#xff0c;涉及众多统计分析方法。本文旨在介绍R语言在生物群落数据统计分析与绘图中的实践应用&#xff0c;结合具体技术要…

100个 Coze 智能体实战案例

&#x1f44b; 家人们&#xff0c;今天我们正式开始 「100个 Coze 智能体实战案例」 系列&#xff01; 为了让关注的小伙伴&#xff0c;去学习到字节的大杀器&#xff0c;coze空间里面的工作流&#xff0c;做agent智能体也好&#xff0c;工作流也好&#xff0c;很多人都会疑惑…

跨越太赫兹鸿沟:高通量实时成像的曙光?

告别蜗牛扫描&#xff0c;实时透视不再是梦 你是否想象过&#xff0c;未来的安检仪能瞬间透视行李箱内的物品&#xff0c;医生能无创“看穿”皮肤下的癌细胞&#xff0c;文物修复师能精准分析千年古画下的每一层颜料&#xff1f;这些科幻场景的实现&#xff0c;正依赖于一种名…

高效开发,升级软件,硬件也要专业

作为开发者的你&#xff0c;在看代码时是否有频繁切换鼠标滚轮的困扰?是否经常会感觉到看代码眼睛干涩? 是时候拥有一台专为程序员打造的专用显示器啦&#xff0c;作为一名程序员&#xff0c;需要写很多项目&#xff0c;都是大工程&#xff0c;我们在修改代码时总希望能显示多…