素材来自网络
链表子串数组题,用双指针别犹豫。
双指针家三兄弟,各个都是万人迷。
快慢指针最神奇,链表操作无压力。
归并排序找中点,链表成环搞判定。
左右指针最常见,左右两端相向行。
反转数组要靠它,二分搜索是弟弟。
滑动窗口老猛男,子串问题全靠它
左右指针滑窗口,一前一后齐头进
自诩十年老司机,怎料农村道路滑。
一不小心滑到了,鼻青脸肿少颗牙。
算法思想很简单,出了bug想升天
前言:文章有点长,这是博主本人的写作风格,大家无需一口气把文章从头到尾看完,只看自己有疑惑的地方即可
力扣上给的是伪代码,对链表的题型无法在自己的本地编辑器上调试,这里给大家一个创建链表的模板可以方便大家调试
def create_list(linklist):
"""
:param linklist:拿来构建链表的数组
:return: head-返回链表的头结点
"""
node_list = []
for i in range(len(linklist)):
node = ListNode()
node.val = linklist[i]
node_list.append(node)
head = node_list[0]
p = head
for node in node_list[1:]:
p.next = node
p = p.next
return head
Leetcode203:移除链表元素:简单题
给你一个链表的头节点
head
和一个整数val
,请你删除链表中所有满足Node.val == val
的节点,并返回 新的头节点
情形1对应解法:不借助于虚拟头结点,直接使用原来的链表来进行移除节点操作,那么删除头结点的操作需要另做考虑
python题解代码
class Solution:
def removeElements(self, head: Optional[ListNode], val: int) -> Optional[ListNode]:
while head and head.val == val: # [7, 7, 7, 7]对于要移除的节点为链表的头结点需要用另外的逻辑来处理
head = head.next
if not head: # 如果链表为空,直接返回
return head
prev = head # prev指向头结点(用来指向待移除节点的前一个节点)
while prev.next: # 注意这里的条件!!!
if prev.next.val == val:
prev.next = prev.next.next
else:
prev = prev.next
return head
情形2对应解法:设置一个虚拟头结点在进行删除操作(设置虚拟头结点后,对原链表中头结点则无需做特殊处理)
python题解代码
class Solution:
def removeElements(self, head: Optional[ListNode], val: int) -> Optional[ListNode]:
if not head:
return head
dummy = ListNode() # 创建一个虚拟头结点
dummy.next = head # 和原链表连接起来
prev = dummy # prev指针指向虚拟头结点
while prev.next:
if prev.next.val == val:
prev.next = prev.next.next
else:
prev = prev.next
return dummy.next
注意上面prev
指针为什么不直接指向待删除的节点,第二个while
循环的条件中为什么是while prev.next
而不是while prev
,别急,第二题中会有详细介绍为什么
Leetcode19:删除链表的倒数第 N 个结点:中等题 详情请点击链接看原题
给你一个链表,删除链表的倒数第
n
个结点,并且返回链表的头结点
题目提示中:链表中结点的数目为sz
,1 <= sz <= 30
,1 <= n <= sz
,所以我们不用担心n
会超出链表的长度
快慢指针大显神威
step1:题目要求返回链表的头结点,所以这里我们创建一个虚拟头结点,让它的next
指针指向head
【常规操作】用于最后返回链表的头结点
step2:快慢指针同时指向头结点head
,快指针先行 n
步,然后快慢指针同时移动,当快指针指向最后一个节点(即 fast.next=None 的时候)
,慢指针指向节点的下一个节点(slow.next)
即我们要删除的倒数第n个节点
step3:快慢指针同时移动之前需要先判断快指针是否指向末尾,如果快指针为None
说明,n
正好等于链表的长度即要删除的倒数第 n
个节点正好是正数第1
个节点
python题解代码
class Solution:
def removeNthFromEnd(self, head: Optional[ListNode], n: int) -> Optional[ListNode]:
dummy_head = ListNode() # 创建一个虚拟头结点
dummy_head.next = head
slow, fast = head, head # 快慢指针同时指向链表头结点
for i in range(n):
fast = fast.next
if not fast: # 如果快指针指到头了,第一个节点就是待删除的节点
return slow.next
while fast.next: # 注意这里的条件 !!!
fast = fast.next
slow = slow.next
slow.next = slow.next.next # 删除 slow.next 节点操作
return dummy_head.next
注:请同学们思考,为什么快指针指向最后一个节点的时候,慢指针指向节点的下一个节点才是我们要删除的倒数第n
个节点呢?
假设链表的长度为
5
,我们要删除倒数第2
个节点,同学们可以在纸上画一下,我们先让快指针移动2
步,快慢指针同时移动,当快指针指向None
的时候,慢指针正好指向倒数第2
个节点(即我们要删除的节点)
But…
但由于链表的特性,对链表的删除操作而言,我们是无法直接删除某个指针所指向的节点的,但我们可以很轻松的删除该指针指向的节点的下一个节点,所以我们必须要让
slow
指针停留在待删除节点的前一个位置,所以我们让fast
指针指向最后一个节点,slow
指向待删除节点的前驱结点
的时候就跳出循环
Leetcode237:删除链表中的节点:中等题 详情请点击链接看原题
有一个单链表的
head
,我们想删除它其中的一个节点node
,给你一个需要删除的节点node
。在本题中你将无法访问头结点head
题目的限制条件:链表的所有值都是唯一的,并且保证给定的节点node
不是链表中的最后一个节点(这里不做过多赘述,请看原题)
题目分析
我们删除链表中节点的操作一般是修改要删除节点的上一个节点的指针,将该指针指向要删除节点的下一个节点
相信同学们看到这道题的第一反应肯定很懵,要你删除链表中的节点却没有给出链表头结点head
,我们如何从头结点
遍历到待删除节点的上一个节点
其实不然,这道题无需你从头结点遍历到指定的节点,题目所给的node
参数已经指向了要删除的节点,but 我们也无法直接删除node
指针指向的节点
狸猫换太子…
从第二题
我们可以知道,既然我们无法直接删除给定的节点,那我们可以将所给节点的下一个节点的val
拿过来覆盖自己本来的val
,然后删除所给节点的下一个节点就可以达到同样的目的
python题解代码
【一共就两行代码】
class Solution:
def deleteNode(self, node):
"""
:type node: ListNode
:rtype: void Do not return anything, modify node in-place instead.
"""
node.val = node.next.val
node.next = node.next.next
Leetcode83:删除排序链表中的重复元素:简单题
给定一个已排序的链表的头
head
, 删除所有重复的元素,使每个元素只出现一次,返回已排序的链表
细心的同学会发现这道题和 Leetcode26-删除有序数组中的重复项 这道题非常类似,只不过这里是有序链表,解题思路完全一致,只不过对链表和数组的处理稍有不一致,这篇文章中有对删除有序数组中的重复项的题解
python题解代码
class Solution:
def deleteDuplicates(self, head: Optional[ListNode]) -> Optional[ListNode]:
if not head:
return head
dummy = ListNode()
dummy.next = head
slow, fast = head, head
while fast:
if slow.val != fast.val:
slow.next = fast
slow = slow.next
fast = fast.next
slow.next = fast
return dummy.next
Leetcode82:删除排序链表中的重复元素 II:中等题
给定一个已排序的链表的头
head
, 删除原始链表中所有重复数字的节点,只留下不同的数字 。返回 已排序的链表
和上一题不同的是这道题中只要存在重复元素,就删除所有包含重复元素的节点,上一题对重复元素的处理是保留一个
Leetcode21:合并两个有序链表:简单题
将两个升序链表合并为一个新的 升序 链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的
python题解代码
class Solution:
def mergeTwoLists(self, list1: Optional[ListNode], list2: Optional[ListNode]) -> Optional[ListNode]:
dummy = ListNode() # 创建一个虚拟头结点
cur = dummy # 创建一个指针指向虚拟头结点
l1, l2 = list1, list2
while l1 and l2:
if l1.val < l2.val:
cur.next = l1
l1 = l1.next
else:
cur.next = l2
l2 = l2.next
cur = cur.next
cur.next = l1 if l1 else l2
return dummy.next
Leetcode23:合并K个升序链表:困难题
给你一个链表数组,每个链表都已经按升序排列。
请你将所有链表合并到一个升序链表中,返回合并后的链表
这道题是一道困难题,关于这道题的解题方法在力扣上流行的有四种,这里主要给大家介绍两种比较难以理解的,至于其他两种,大家可以自行去力扣上查看其他博主的题解
方法1:最小堆(需要具备堆的基础概念)
方法1需要大家对堆的基础知识有一定的了解,如果不熟悉的同学请先去了解一下
最大堆
,最小堆
的概念以及如何进行堆调整
,堆中节点的下沉
与上浮
,没搞清楚这些概念之前这个方法会很难理解
分析
first
一定是某个链表的头结点(因为链表已经升序排列),first
的下一个节点,那么每当我们找到一个节点值最小的节点x
,我们就把节点 x.next
加入【可能是最小节点的集合】中因此我们可以利用最小堆
来充当这个可能是最小节点的集合在了解了上述概念之后其实并不用大家动手写关于堆的代码,python
中有个标准库heapq
里面封装好了关于堆的操作方法,现在让我来给大家介绍一下
heapq.heappush(heap, num):
先创建一个空堆,然后将数据一个一个地添加到堆中。每添加一个数据后,heap
都满足小顶堆的特性
heapq.heappop(heap):
将堆顶的数据出堆,并将堆中剩余的数据构造成新的小顶堆
heapq自动帮我们维护了最小堆,自动帮我们弹出我们需要的最小元素
python题解代码
class Solution:
def mergeKLists(self, lists: List[ListNode]) -> ListNode:
import heapq
dummy = ListNode(0)
p = dummy
head = []
for i in range(len(lists)):
if lists[i]:
heapq.heappush(head, (lists[i].val, i)) # 将所有链表的头结点入堆(这里根据lists[i].val构建最小堆)
lists[i] = lists[i].next # 指针后移
while head:
val, idx = heapq.heappop(head) # 将堆顶的最小元素弹出
p.next = ListNode(val)
p = p.next
if lists[idx]: # 如果弹出的最小节点的下个节点不为空(则有可能为最小)
heapq.heappush(head, (lists[idx].val, idx)) # 继续入堆(重新自动构建最小堆)
lists[idx] = lists[idx].next
return dummy.next
扩展:算法能力强或者对堆的操作比较熟悉的同学可以自己手动实现 heapq.heappush()
和heapq.heappop()
这两个函数实现的功能
heapq.heappush(heap, num)
就是在heap
中插入元素num
然后进行上浮操作维护一个最小堆
heapq.heappop(heap)
则是删除堆顶元素进行下沉操作,有兴趣的同学可以去看下博主的关于堆的另一篇文章
对了堆也是大厂面试中的高频考点,对于这道题而言,主要考察的是你对于链表的操作,在面试中你直接使用python
的heapq
封好好的功能也是没有问题的
方法2:未完待续
Leetcode24:两两交换链表中的节点
给你一个链表,两两交换其中相邻的节点,并返回交换后链表的头节点。你必须在不修改节点内部的值的情况下完成本题(即只能进行节点交换)
方法一:分析
初始时,cur
指向虚拟头结点
这里建议大家画图,能用纸笔画就用纸笔画,身边没纸笔用你的画图工具
注意,链表的索引只能根据上一个节点的next
来找到下一个节点的位置
cur.next = cur.next.next # 步骤一
所以执行完骤一(将头结点指向原本的第一个节点改为指向第二个节点)之后我们无法找到第一个节点
temp1 = cur.next # 先将第一个节点的位置暂存起来
同理执行完步骤二(将第二个节点和链表断开)后我们也无法找到第三个节点
temp2 = cur.next.next.next # 将第三个节点的位置暂存起来
方法1总结
因为要通过改变
cur节点
的next
和cur.next.next节点
的next
的指向来交换cur.next
和cur.next.next
节点
所以我们需要先将cur节点
和cur.next.next节点
这两个节点原来的指向暂存起来,即temp1 = cur.next, temp2 = cur.next.next.next
python题解代码
class Solution:
def swapPairs(self, head: Optional[ListNode]) -> Optional[ListNode]:
dummy = ListNode()
dummy.next = head
cur = dummy
while cur.next and cur.next.next:
temp1 = cur.next
temp2 = cur.next.next.next
cur.next = cur.next.next
cur.next.next = temp1
cur.next.next.next = temp2
cur = cur.next.next # cur移动两位,准备下一轮交换
return dummy.next
方法2分析:递归法
class Solution:
def swapPairs(self, head: Optional[ListNode]) -> Optional[ListNode]:
if not head or not head.next:
return head
# 待翻转的两个node分别是pre和cur
pre = head
cur = head.next
next_node = head.next.next
cur.next = pre
pre.next = self.swapPairs(next_node)
return cur
Leetcode160:相交链表:简单题 详情请点击链接看原题
给你两个单链表的头节点
headA
和headB
,请你找出并返回两个单链表相交的起始节点。如果两个链表不存在相交节点,返回null
分析
严格证明取自力扣K神大佬题解
设【第一个公共节点为】node
,【链表 headA】的节点数量为 a
,【链表 headB】的节点数量为 b
,【两链表的公共尾部】的节点数量为 c
,则有:
headA
到 node
前共有 a - c
个节点headB
到 node
前共有 b - c
个节点A
先遍历完链表 headA
,再开始遍历链表 headB
,当走到 node
时,共走步数为:a + (b − c)
B
先遍历完链表 headB
,再开始遍历链表 headA
,当走到 node
时,共走步数为:b + (a − c)
因为a + (b - c) = b + (a - c)
,此时指针A
, B
重合(两指针相遇即链表相交),并有两种情况:
case1:若两链表有公共尾部(
即c > 0
):指针A
,B
同时指向第一个公共节点node
case2:若两链表无公共尾部(即c=0
),指针A
,B
同时指向None
python题解代码
class Solution:
def getIntersectionNode(self, headA: ListNode, headB: ListNode) -> ListNode:
A, B = headA, headB
while A != B: # 当A==B时推出循环,两指针同时扫描到交点或同时指向 None
A = A.next if A else headB
B = B.next if B else headA
return A
换种更容易理解的思路,若两链表相交,交点为c
,链表A的长度为a + c
,链表B的长度为b + c
,两个头节点指针分别走过对方来时的路则有a + c + b + c = b + c + a + c
,则证明两链表相交与一点,若不相交,两头节点互相走过对方来时的路有a + b = b + a
,两指针刚好同时指向None
两个人走的路一样,走路的速度一样,两条路有交点必在交点相遇,没交点则在在终点(None)相遇
Leetcode1721:交换链表中的节点:中等题 详情请点击链接看原题
给你链表的头节点
head
和一个整数k
。
交换 链表正数第k
个节点和倒数第k
个节点的值后,返回链表的头节点(链表 从1
开始索引
分析
本题有两种解法,值交换(偷天换日)和节点交换,力扣上博主的题解总结的很好,这里只介绍第一种解法,节点交换需要考虑的边界条件太复杂,不想写了
方法1:值交换-找到倒数第 k 个节点和第 k 个节点后进行值交换
找第
k
个节点非常简单,找倒数第k
个节点和前文中的删除倒数第k个节点
的方法是一样的
python题解代码
class Solution:
def swapNodes(self, head: Optional[ListNode], k: int) -> Optional[ListNode]:
slow, fast = head, head
# 因为从头节点(第一个节点)开始遍历,循环k-1次即指向第k个节点
for _ in range(k - 1):
fast = fast.next
cur = fast
# 同理当cur指向最后一个节点(cur.next为空)的时候,slow正好指向倒数第k个节点
while cur.next:
slow = slow.next
cur = cur.next
fast.val, slow.val = slow.val, fast.val # 第k个节点和倒数第k个节点做值交换
return head
Leetcode141:环形链表I:简单题 详情请点击链接看原题
给你一个链表的头节点
head
,判断链表中是否有环
分析
设有两个指针 slow
和 fast
初始时均指向头结点,slow
向后走一次,fast
向后走两次,在每轮移动之后,fast
和 slow
的距离就会增加 1
,如果链表有环,fast
指针一定先进入环中(继续移动),等slow
指针进入环中后,二者继续移动,fast
指针和slow
指针的距离+1,可是在环中,距离+1也意味着距离-1(距离拉开的同时距离也正在缩小)
根据物理学上的相对运动来说,其实就相当于
slow
指针静止,fast
指针每次移动一个距离向slow
指针靠近,所以二者是一定会在环中相遇的
python题解代码
class Solution:
def hasCycle(self, head: Optional[ListNode]) -> bool:
slow, fast = head, head
while fast and fast.next:
slow = slow.next
fast = fast.next.next
if fast == slow:
return True
return False
Leetcode142:环形链表II:中等题 详情请点击链接看原题
给定一个链表的头节点
head
,返回链表开始入环的第一个节点。 如果链表无环,则返回null
分析
这道题的题解分析很多博主都给出非常严格的数学证明,在本文中,作者尽量用最少的文字简化分析让大家能够快速理解
从上一题可以知道,
slow
走一步,fast
走两步,链表有环则二者一定会相遇,假设从头结点到环形入口节点 的节点数为x
。 环形入口节点到相遇节点节点数为y
。 从相遇节点再到环形入口节点节点数为z
从上一题的分析中我们可以知道,fast
指针不可能跨过slow
指针而不与slow
指针相遇,所以slow
指针不存在绕环一圈的情况
则相遇时slow
指针走过的节点数为 x + y
, fast
指针走过的节点数:x + y + n (y + z)
,x
可能很长,环很短,fast
指针在环中走了n
圈才遇到slow
指针
fast
指针走过的节点数 =slow
指针走过的节点数 *2
(x + y) * 2 = x + y + n (y + z)
,利用初中所学的数学知识进行化简,x = (n - 1) (y + z) + z
注意这里 n
一定是大于等于 1
的,因为 fast
指针至少要多走一圈才能相遇 slow
指针,当 n
为 1
的时候,公式就化解为 x = z
x = z
:意味着从头结点
出发一个指针,从相遇节点
也出发一个指针,这两个指针每次只走一个节点, 那么当这两个指针相遇的时候就是环形入口的节点
到此,我们可以在相遇节点处定义一个指针index1
,在头结点处定义一个指针index2
,index1
和 index2
同时移动,每次移动一个节点,那么它们相遇的地方就是环形的入口节点,如果 n > 1
则说明 index1
指针在环里多转了 (n - 1)
圈再遇到 index2
,相遇节点依然是环形的入口节点
python题解代码
class Solution:
def detectCycle(self, head: Optional[ListNode]) -> Optional[ListNode]:
slow, fast = head, head
while fast and fast.next:
fast = fast.next.next
slow = slow.next
if fast == slow:
index1 = fast # 定义index1指向相遇节点
index2 = head # 定义index2指向头结点
while index2 != index1: # 同时移动index1和index2直到二者相遇
index1 = index1.next
index2 = index2.next
return index1
return None
Leetcode206:反转链表:简单题 详情请点击链接看原题
给你单链表的头节点
head
,请你反转链表,并返回反转后的链表
方法1: 头插法反转单链表
python题解代码
class Solution:
def reverseList(self, head: Optional[ListNode]) -> Optional[ListNode]:
dummy = ListNode()
cur_node = head
while cur_node:
next_node = cur_node.next # 将头结点断链,保存剩余链表到 next_node
cur_node.next = dummy.next
dummy.next = cur_node
cur_node = next_node # cur_node 重新指向剩余链表的头结点
return dummy.next
方法2: 递归法
Leetcode2:两数相加:中等题 详情请点击链接看原题
使用链表实现大数加法
给你两个 非空 的链表,表示两个非负的整数。它们每位数字都是按照 逆序 的方式存储的,并且每个节点只能存储 一位 数字。
请你将两个数相加,并以相同形式返回一个表示和的链表。
你可以假设除了数字0
之外,这两个数都不会以0
开头
分析
0
如987 + 23 = 987 + 023
数不以
0
开头,但是当某个数较短的时候需要在前面补0
,数字在链表中是按照 逆序 的方式存储的,所以当我们遍历到链表末尾的时候若其中一个链表不为空另一个链表为空,则需要在链表的后面补0
为了达到前面说的在数字前面补0
保证数字对齐
7——>8——>9
3——>2——>0
1
,则在新链表最前方添加结点 1
python题解代码
class Solution:
def addTwoNumbers(self, l1: Optional[ListNode], l2: Optional[ListNode]) -> Optional[ListNode]:
dummy = ListNode()
cur_node = dummy
carry = 0 # 进位
while l1 or l2:
x = 0 if not l1 else l1.val # 如果一个链表为空另一个不为空则需要在后面补0
y = 0 if not l2 else l2.val
total = x + y + carry # 从两个数字的末尾(两个链表的头)开始计算
carry = total / 10 # 记录当前两个数之和的进位
total %= 10 # 取个位
cur_node.next = ListNode(total) # 将实例化的结点放在头结点dummy之后
cur_node = cur_node.next # cur_node指针右移准备计算下一位
if l1:
l1 = l1.next # l1不为空则l1右移
if l2:
l2 = l2.next # l2不为空则l2右移
if carry == 1: # 如果两个链表遍历完毕后进位值为 1,则在新链表最末尾(即数的最高位)添加结点 1
cur_node.next = ListNode(carry)
return dummy.next
Leetcode146:LRU缓存:中等题 详情请点击链接看原题
请你设计并实现一个满足 LRU (最近最少使用) 缓存 约束的数据结构
博主水平有限,算法设计思路来源于力扣大佬题解,博主只在这里做个总结,方便大家和本人理解
要让put
和get
方法的时间复杂度为O(1)
,cache
这个数据结构的必要条件
1.
cache
中的元素必须有时序以区分最近使用和久未使用的数据,容量满了以后要删除最久未使用的那个元素
2.我们要在cache
中快速找某个key
是否已存在并得到对应的val
3.每次访问cache
中的某个key
,需要将这个元素变为最近使用的,也就是说cache
要支持在任意位置快速插入和删除元素
这个数据接口应具备如下节点:
1.支持快速查找
2.保存访问的先后顺序,在末尾加入一项,去除最前端一项
3.将队列中的某一项移到末尾
哈希表查找快,但数据无固定顺序,链表有顺序之分但是查找慢,所以二者结合一下形成一种新的数据结构,这就是大名鼎鼎的哈希链表 LinkedHashMap
1.默认
put
操作从链表尾部添加元素,那么显然越靠近尾部的元素就是最近使用的,越靠头部的元素就是最久未使用的(因为是双链表,你也可以在链表头部添加元素,把头部元素当成是最近使用的元素)
2.对于某一个key
,我们可以通过哈希表快速定位到链表中的结点从而取得对应的val
3.链表虽然支持通过修改指针在任意位置插入和删除,只不过传统的链表无法按照索引快速访问某一个位置的元素,而这里借助于哈希表,通过key
快速映射到任意一个链表结点,然后进行插入和删除
这里为啥用双链表而不是单链表?
从前几题的分析我们可以知道删除一个节点不光要得到该节点本身的指针,也需要操作其前驱结点的指针
,而我们用哈希表只能定位到需删除的节点,无法定位到其前驱结点,而双向链表就支持直接查找前驱,保证操作的时间复杂度为O(1)
python题解代码
class ListNode(object): # 定义双链表的结点类(注意这里为啥要使用双向链表)
def __init__(self, key=None, value=None):
self.key = key
self.value = value
self.prev = None
self.next = None
class LRUCache:
def __init__(self, capacity: int):
self.capacity = capacity
self.hashmap = {}
# 初始化一个虚拟头结点和虚拟尾结点用作表头和表尾,其余节点放在中间
self.head = ListNode()
self.tail = ListNode()
self.head.next = self.tail
self.tail.prev = self.head
def move_node_to_tail(self, key):
# 1.先根据 key 在哈希表中找到对应的双链表中的节点
node = self.hashmap[key]
# 2.将该节点的前后节点相连
node.prev.next = node.next
node.next.prev = node.prev
# 3.之后将node插入到尾结点前
node.prev = self.tail.prev
node.next = self.tail
self.tail.prev.next = node
self.tail.prev = node
def get(self, key: int) -> int:
if key in self.hashmap:
# 如果已经在链表中了就把它移动到末尾(变成最新访问的)
self.move_node_to_tail(key)
res = self.hashmap.get(key, -1) # 在哈希表中查找对应的key
if res == -1:
return res
else:
return res.value # 返回链表中对应的value
def put(self, key: int, value: int) -> None:
# 1.如果key本身已经在哈希表中就不需要在链表中加入新的结点,但是需要更新字典对应结点的value
if key in self.hashmap:
self.hashmap[key].value = value
# 2.之后将刚刚访问的该结点移到链表末尾
self.move_node_to_tail(key)
else:
# 1.如果容量已满则去掉最久未使用的节点
if len(self.hashmap) == self.capacity:
# 1.1 去掉哈希表对应项
self.hashmap.pop(self.head.next.key)
# 1.2 去掉最久没有被访问过的结点,即头结点之后的结点
self.head.next = self.head.next.next
self.head.next.prev = self.head
# 如果不在且容量未满的情况下就插入到尾结点之前
new = ListNode(key, value)
self.hashmap[key] = new
new.prev = self.tail.prev
new.next = self.tail
self.tail.prev.next = new
self.tail.prev = new
其实对于本题来说核心考察点就是双链表的插入和删除操作,需要注意细节和前后顺序
本文给大家总结了大厂面试中喜欢考察的关于链表的相关题型,对于链表题,双指针的快慢指针通常是最常用的,注意一下链表的插入和删除操作中的顺序要求,顺序乱了整个链表就断裂了,主要帮助大家总结了考点以及清晰明了的题解方便大家理解,如果你觉得本文对你有帮助的话,还请点赞收藏转发,最后,祝大家都能找到心仪的工作呀~