当前位置: 首页 > news >正文

列表 模版题单 12

链表

基本技能

链表相关的核心点

  • null/nil 异常处理
  • dummy node 哑巴节点
  • 快慢指针
  • 插入一个节点到排序链表
  • 从一个链表中移除一个节点
  • 翻转链表
  • 合并两个链表
  • 找到链表的中间节点

常见题型

remove-duplicates-from-sorted-list

给定一个排序链表,删除所有重复的元素,使得每个元素只出现一次。

class Solution:def deleteDuplicates(self, head: ListNode) -> ListNode:if head is None:return headcurrent = headwhile current.next is not None:if current.next.val == current.val:current.next = current.next.nextelse:current = current.nextreturn head

remove-duplicates-from-sorted-list-ii

给定一个排序链表,删除所有含有重复数字的节点,只保留原始链表中 没有重复出现的数字。

  • 思路:链表头结点可能被删除,所以用 dummy node 辅助删除
class Solution:def deleteDuplicates(self, head: ListNode) -> ListNode:if head is None:return headdummy = ListNode(next=head)current, peek = dummy, headfind_dup = Falsewhile peek.next is not None:if peek.next.val == peek.val:find_dup = Truepeek.next = peek.next.nextelse:if find_dup:find_dup = Falsecurrent.next = current.next.nextelse:current = current.nextpeek = peek.nextif find_dup:current.next = current.next.nextreturn dummy.next

注意点
• A->B->C 删除 B,A.next = C
• 删除用一个 Dummy Node 节点辅助(允许头节点可变)
• 访问 X.next 、X.value 一定要保证 X != nil

reverse-linked-list

反转一个单链表。

  • 思路:将当前结点放置到头结点
class Solution:def reverseList(self, head: ListNode) -> ListNode:if head is None:return headtail = headwhile tail.next is not None:# put tail.next to head  tmp = tail.nexttail.next = tail.next.nexttmp.next = headhead = tmpreturn head
  • Recursive method is tricky
class Solution:def reverseList(self, head: ListNode) -> ListNode:if head is None or head.next is None:return headrev_next = self.reverseList(head.next)head.next.next = headhead.next = Nonereturn rev_next

reverse-linked-list-ii

反转从位置 mn 的链表。请使用一趟扫描完成反转。

  • 思路:先找到 m 处, 再反转 n - m 次即可
class Solution:def reverseBetween(self, head: ListNode, m: int, n: int) -> ListNode:if head is None:return headn -= m # number of times of reversecurr = dummy = ListNode(next=head)while m > 1: # find node at m - 1curr = curr.nextm -= 1start = curr.nextwhile n > 0: # reverse n - m timestmp = start.nextstart.next = tmp.nexttmp.next = curr.nextcurr.next = tmpn -= 1return dummy.next

merge-two-sorted-lists

将两个升序链表合并为一个新的升序链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。

  • 思路:通过 dummy node 链表,连接各个元素
class Solution:def mergeTwoLists(self, l1: ListNode, l2: ListNode) -> ListNode:tail = dummy = ListNode()while l1 is not None and l2 is not None:if l1.val > l2.val:tail.next = l2l2 = l2.nextelse:tail.next = l1l1 = l1.nexttail = tail.nextif l1 is None:tail.next = l2else:tail.next = l1return dummy.next

partition-list

给定一个链表和一个特定值 x,对链表进行分隔,使得所有小于 x 的节点都在大于或等于 x 的节点之前。

  • 思路:将大于 x 的节点,放到另外一个链表,最后连接这两个链表
class Solution:def partition(self, head: ListNode, x: int) -> ListNode:p = l = ListNode()q = s = ListNode(next=head)while q.next is not None:if q.next.val < x:q = q.nextelse:p.next = q.nextq.next = q.next.nextp = p.nextp.next = Noneq.next = l.nextreturn s.next

哑巴节点使用场景

当头节点不确定的时候,使用哑巴节点

sort-list

O(n log n) 时间复杂度和常数级空间复杂度下,对链表进行排序。

  • 思路:归并排序,slow-fast找中点
class Solution:def _merge(self, l1, l2):tail = l_merge = ListNode()while l1 is not None and l2 is not None:if l1.val > l2.val:tail.next = l2l2 = l2.nextelse:tail.next = l1l1 = l1.nexttail = tail.nextif l1 is not None:tail.next = l1else:tail.next = l2return l_merge.nextdef _findmid(self, head):slow, fast = head, head.nextwhile fast is not None and fast.next is not None:fast = fast.next.nextslow = slow.nextreturn slow# 找到中点,断开再合并def sortList(self, head: ListNode) -> ListNode:if head is None or head.next is None:return headmid = self._findmid(head)tail = mid.nextmid.next = None # break from middlereturn self._merge(self.sortList(head), self.sortList(tail))

注意点

  • 快慢指针 判断 fast 及 fast.Next 是否为 nil 值
  • 递归 mergeSort 需要断开中间节点
  • 递归返回条件为 head 为 nil 或者 head.Next 为 nil

reorder-list

给定一个单链表 LLL→…→L__nL
将其重新排列后变为: LL__nLL__nLL__n→…

  • 思路:找到中点断开,翻转后面部分,然后合并前后两个链表
class Solution:def reverseList(self, head: ListNode) -> ListNode:prev, curr = None, headwhile curr is not None:curr.next, prev, curr = prev, curr, curr.nextreturn prevdef reorderList(self, head: ListNode) -> None:"""Do not return anything, modify head in-place instead."""if head is None or head.next is None or head.next.next is None:returnslow, fast = head, head.nextwhile fast is not None and fast.next is not None:fast = fast.next.nextslow = slow.nexth, m = head, slow.nextslow.next = Nonem = self.reverseList(m)while h is not None and m is not None:p = m.nextm.next = h.nexth.next = mh = h.next.nextm = preturn

linked-list-cycle

给定一个链表,判断链表中是否有环。

  • 思路1:Hash Table 记录所有结点判断重复,空间复杂度 O(n) 非最优,时间复杂度 O(n) 但必然需要 n 次循环
  • 思路2:快慢指针,快慢指针相同则有环,证明:如果有环每走一步快慢指针距离会减 1,空间复杂度 O(1) 最优,时间复杂度 O(n) 但循环次数小于等于 n
    外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传
class Solution:def hasCycle(self, head: ListNode) -> bool:slow = fast = headwhile fast is not None and fast.next is not None:slow = slow.nextfast = fast.next.nextif fast == slow:return Truereturn False

linked-list-cycle-ii

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

  • 思路:快慢指针,快慢相遇之后,慢指针回到头,快慢指针步调一致一起移动,相遇点即为入环点。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

class Solution:def detectCycle(self, head: ListNode) -> ListNode:slow = fast = headwhile fast is not None and fast.next is not None:slow = slow.nextfast = fast.next.nextif slow == fast:slow = headwhile fast != slow:fast = fast.nextslow = slow.nextreturn slowreturn None

坑点

  • 指针比较时直接比较对象,不要用值比较,链表中有可能存在重复值情况
  • 第一次相交后,快指针需要从下一个节点开始和头指针一起匀速移动

注意,此题中使用 slow = fast = head 是为了保证最后找环起始点时移动步数相同,但是作为找中点使用时一般用 fast=head.Next 较多,因为这样可以知道中点的上一个节点,可以用来删除等操作。

  • fast 如果初始化为 head.Next 则中点在 slow.Next
  • fast 初始化为 head,则中点在 slow

palindrome-linked-list

请判断一个链表是否为回文链表。

  • 思路:O(1) 空间复杂度的解法需要破坏原链表(找中点 -> 反转后半个list -> 判断回文),在实际应用中往往还需要复原(后半个list再反转一次后拼接),操作比较复杂,这里给出更工程化的做法
class Solution:def isPalindrome(self, head: ListNode) -> bool:s = []slow = fast = headwhile fast is not None and fast.next is not None:s.append(slow.val)slow = slow.nextfast = fast.next.nextif fast is not None:slow = slow.nextwhile len(s) > 0:if slow.val != s.pop():return Falseslow = slow.nextreturn True

copy-list-with-random-pointer

给定一个链表,每个节点包含一个额外增加的随机指针,该指针可以指向链表中的任何节点或空节点。
要求返回这个链表的 深拷贝。

  • 思路1:hash table 存储 random 指针的连接关系
class Solution:def copyRandomList(self, head: 'Node') -> 'Node':if head is None:return Noneparent = collections.defaultdict(list)out = Node(0)o, n = head, outwhile o is not None:n.next = Node(o.val)n = n.nextif o.random is not None:parent[o.random].append(n)o = o.nexto, n = head, out.nextwhile o is not None:if o in parent:for p in parent[o]:p.random = no = o.nextn = n.nextreturn out.next
  • 思路2:复制结点跟在原结点后面,间接维护连接关系,优化空间复杂度,建立好新 list 的 random 链接后分离
class Solution:def copyRandomList(self, head: 'Node') -> 'Node':if head is None:return Nonep = headwhile p is not None:p.next = Node(p.val, p.next)p = p.next.nextp = headwhile p is not None:if p.random is not None:p.next.random = p.random.nextp = p.next.nextnew = head.nexto, n = head, newwhile n.next is not None:o.next = n.nextn.next = n.next.nexto = o.nextn = n.nexto.next = Nonereturn new

总结

链表必须要掌握的一些点,通过下面练习题,基本大部分的链表类的题目都是手到擒来~

  • null/nil 异常处理
  • dummy node 哑巴节点
  • 快慢指针
  • 插入一个节点到排序链表
  • 从一个链表中移除一个节点
  • 翻转链表
  • 合并两个链表
  • 找到链表的中间节点

练习

  • remove-duplicates-from-sorted-list
  • remove-duplicates-from-sorted-list-ii
  • reverse-linked-list
  • reverse-linked-list-ii
  • merge-two-sorted-lists
  • partition-list
  • sort-list
  • reorder-list
  • linked-list-cycle
  • linked-list-cycle-ii
  • palindrome-linked-list
  • copy-list-with-random-pointer

文章转载自:
http://biro.hnsdj.cn
http://biome.hnsdj.cn
http://alkalize.hnsdj.cn
http://apopemptic.hnsdj.cn
http://bemoisten.hnsdj.cn
http://besot.hnsdj.cn
http://absorbed.hnsdj.cn
http://botcher.hnsdj.cn
http://bedin.hnsdj.cn
http://capillarity.hnsdj.cn
http://brushy.hnsdj.cn
http://cannibalise.hnsdj.cn
http://carbamide.hnsdj.cn
http://chromaticity.hnsdj.cn
http://antiicer.hnsdj.cn
http://antisickling.hnsdj.cn
http://betony.hnsdj.cn
http://aftersound.hnsdj.cn
http://abe.hnsdj.cn
http://american.hnsdj.cn
http://checker.hnsdj.cn
http://antecedent.hnsdj.cn
http://abwatt.hnsdj.cn
http://bequeathal.hnsdj.cn
http://agreeable.hnsdj.cn
http://calydonian.hnsdj.cn
http://cetus.hnsdj.cn
http://butterscotch.hnsdj.cn
http://bentwood.hnsdj.cn
http://blepharoplasty.hnsdj.cn
http://www.dtcms.com/a/201054.html

相关文章:

  • Windows 如何安装CUDA
  • LeetCode 字符串类题目解析与 Java 实现指南(深度优化版)
  • leetcode 每日一题 1931. 用三种不同颜色为网格涂色
  • gtest 库的安装和使用
  • python打卡第30天
  • dbhub MCP服务搭建
  • cursor+MCP系列:12306-MCP车票查询工具
  • Logrotate:配置日志轮转、高效管理Linux日志文件
  • 秒删node_modules 极速删除 (rimraf工具)
  • 非金属材料的分类及应用
  • C++寻位映射的奇幻密码:哈希
  • NIFI 2.40简介及部署
  • unordered_map/set常用接口及模拟实现
  • 网络请求和状态管理
  • ebpf-verifier
  • Flink 非确定有限自动机NFA
  • JavaScript:PC端特效--缓动动画
  • SHELL练习题(1-11题)记录(牛客)
  • Python训练营打卡——DAY30(2025.5.19)
  • python fastapi + react, 写一个图片 app
  • 英特尔硬件笔试面试题型解析
  • YOLO模型使用jupyterlab的方式进行预测/推理(示例)
  • nginx 流量控制
  • ubuntu22.04 卸载ESP-IDF
  • 20250519使用TF卡将NanoPi NEO core开发板刷机为Ubuntu core22.04.3系统完成之后执行poweroff自动关机
  • 实验-使用递归计算阶乘-RISC-V(计算机组成原理)
  • AM32电调学习解读九:ESC上电启动关闭全流程波形分析
  • linux服务器与时间服务器同步时间
  • CSS 选择器入门
  • python文件部署docker,容器路径与系统路径映射