# 定义双向链表节点类
# 每个节点需要存储:key、value、前驱指针、后继指针
class DLinkedNode:
def __init__(self, key=0, value=0):
self.key = key # 必须存key!删除链表尾节点时,要靠它去哈希表删数据
self.value = value # 缓存存储的值
self.prev = None # 前驱节点指针
self.next = None # 后继节点指针
# LRU 缓存实现类
# 核心:哈希表 O(1) 查找 + 双向链表 O(1) 增删
class LRUCache:
# 初始化构造方法
def __init__(self, capacity: int):
self.capacity = capacity # 缓存最大容量(上限)
self.size = 0 # 当前缓存里实际存了多少数据
self.cache = {} # 哈希表:key -> 双向链表节点,实现 O(1) 查找
# 创建【虚拟头节点】和【虚拟尾节点】
# 作用:不用判断空链表、头插、尾删的边界情况
self.head = DLinkedNode()
self.tail = DLinkedNode()
# 初始化双向链表:head <-> tail
self.head.next = self.tail
self.tail.prev = self.head
# 查询操作:根据 key 获取 value
def get(self, key: int) -> int:
# 如果 key 不在缓存里,返回 -1
if key not in self.cache:
return -1
# key 存在:通过哈希表找到对应的节点
node = self.cache[key]
# 访问过了,把节点移到链表头部(标记为【最近使用】)
self.moveToHead(node)
# 返回节点的值
return node.value
# 插入/更新操作
def put(self, key: int, value: int) -> None:
if key in self.cache:
# 情况1:key 已存在
# 找到节点,更新 value
node = self.cache[key]
node.value = value
# 访问过,移到头部
self.moveToHead(node)
else:
# 情况2:key 不存在,新建节点
new_node = DLinkedNode(key, value)
# 加入哈希表
self.cache[key] = new_node
# 缓存数量 +1
self.size += 1
# 如果缓存满了,需要删除【最久未使用】的节点(链表尾部)
if self.size > self.capacity:
# 删除尾部节点
tail_node = self.removeTail()
# 同时在哈希表里删除这个 key
del self.cache[tail_node.key]
# 缓存数量 -1
self.size -= 1
# 把新节点加到链表头部
self.addToHead(new_node)
# 工具方法:把一个节点【添加到链表头部】
def addToHead(self, node: DLinkedNode):
# 新节点的前驱指向 head
node.prev = self.head
# 新节点的后继指向 head 原来的 next
node.next = self.head.next
# 原来的头节点的前驱,指向新节点
self.head.next.prev = node
# head 的 next 指向新节点
self.head.next = node
# 工具方法:从双向链表中【删除指定节点】
def removeNode(self, node: DLinkedNode):
# 拿到要删除节点的 前驱 和 后继
prev_node = node.prev
next_node = node.next
# 直接跳过当前节点,让前后节点互相连接
prev_node.next = next_node
next_node.prev = prev_node
# 工具方法:把节点【移动到头部】
# 两步:先删除,再插入头部
def moveToHead(self, node: DLinkedNode):
self.removeNode(node)
self.addToHead(node)
# 工具方法:【删除尾部节点】(最久未使用)
def removeTail(self) -> DLinkedNode:
# 尾节点的前驱,就是真正的最后一个有效节点
tail_node = self.tail.prev
# 从链表中删掉它
self.removeNode(tail_node)
# 返回被删掉的节点(用于去哈希表删 key)
return tail_node
# Your LRUCache object will be instantiated and called as such:
# obj = LRUCache(capacity)
# param_1 = obj.get(key)
# obj.put(key,value)
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, val=0, next=None):
# self.val = val
# self.next = next
class Solution:
# 合并两个链表
def merge(self, h1: Optional[ListNode], h2: Optional[ListNode]) -> Optional[ListNode]:
cur = dummy = ListNode(0)
while h1 and h2:
if h1.val < h2.val:
cur.next = h1
h1 = h1.next
else:
cur.next = h2
h2 = h2.next
cur = cur.next
cur.next = h1 if h1 else h2
return dummy.next
def sortList(self, head: Optional[ListNode]) -> Optional[ListNode]:
if not head or not head.next:
return head
# 获取链表总长度
n = 0
cur = head
while cur:
n += 1
cur = cur.next
dummy = ListNode(0, head)
intv = 1
while intv < n:
pre, cur = dummy ,dummy.next
while cur:
# 截取第一段有序链表
h1 = cur
for _ in range(intv - 1):
if cur and cur.next:
cur = cur.next
else:
break
# 获取第二段有序链表,并断开第一段链表
h2 = cur.next
cur.next = None
cur = h2
for _ in range(intv - 1):
if cur and cur.next:
cur = cur.next
else:
break
# 获取下一轮开始的指针,并断开第二段链表
next_node = None
if cur:
next_node = cur.next
cur.next = None
# 合并两个链表
merged = self.merge(h1, h2)
pre.next = merged
while pre.next:
pre = pre.next
cur = next_node
intv *= 2
return dummy.next
class Solution:
def copyRandomList(self, head: 'Optional[Node]') -> 'Optional[Node]':
# 边界情况:如果原链表为空,直接返回空
if not head:
return None
# 创建哈希表,用于存储 原节点 -> 新复制节点 的映射关系
node_map = {}
# 定义游标指针,从头节点开始遍历
cur = head
# 第一次遍历:创建所有新节点,只赋值val,建立原节点和新节点的映射
while cur:
# 根据当前原节点的值,创建一个新的复制节点
new_node = Node(cur.val)
# 把 原节点:新节点 存入字典,方便后续查找对应关系
node_map[cur] = new_node
# 游标向后移动,继续处理下一个原节点
cur = cur.next
# 第二次遍历:给新节点设置 next 和 random 指针
cur = head # 重置游标,回到链表头
while cur:
# 从字典中取出当前原节点对应的新节点
new_node = node_map[cur]
# 新节点的next = 原节点next对应的新节点(没有则为None)
new_node.next = node_map.get(cur.next, None)
# 新节点的random = 原节点random对应的新节点(没有则为None)
new_node.random = node_map.get(cur.random, None)
# 游标向后移动
cur = cur.next
# 返回复制链表的头节点(原头节点对应的新节点)
return node_map[head]
class Solution:
def copyRandomList(self, head: 'Optional[Node]') -> 'Optional[Node]':
# 边界情况:链表为空直接返回
if not head:
return None
# 第一步:在每个原节点后面插入对应的复制节点
cur = head
while cur:
# 创建当前节点的复制节点
copy = Node(cur.val)
# 复制节点的next指向原节点的next
copy.next = cur.next
# 原节点的next指向复制节点,完成插入
cur.next = copy
# 游标移动到下一个原节点(跳过刚插入的复制节点)
cur = copy.next
# 第二步:给所有复制节点设置 random 指针
cur = head # 重置游标
while cur:
# 如果原节点有random指向,那么复制节点的random = 原节点random的下一个节点(对应复制节点)
if cur.random:
cur.next.random = cur.random.next
# 每次跳两步,只遍历原节点
cur = cur.next.next
# 第三步:将原链表和复制链表分离,得到最终的深拷贝链表
cur = head
copy_head = head.next # 记录复制链表的头节点,最后要返回
copy_cur = copy_head # 复制链表的游标
while cur:
# 原节点的next恢复为原next(跳过复制节点)
cur.next = copy_cur.next
# 原链表游标后移
cur = cur.next
# 如果还有后续节点,复制链表游标继续后移
if cur:
copy_cur.next = cur.next
copy_cur = copy_cur.next
# 返回复制好的新链表头
return copy_head