力扣学习笔记day12

题146.LRU缓存机制

题意

运用你所掌握的数据结构,设计和实现一个 LRU (最近最少使用) 缓存机制 。
实现 LRUCache 类:

  • LRUCache(int capacity) 以正整数作为容量 capacity 初始化 LRU 缓存
  • int get(int key) 如果关键字 key 存在于缓存中,则返回关键字的值,否则返回 -1 。
  • void put(int key, int value) 如果关键字已经存在,则变更其数据值;如果关键字不存在,则插入该组「关键字-值」。当缓存容量达到上限时,它应该在写入新数据之前删除最久未使用的数据值,从而为新的数据值留出空间。

进阶: 你是否可以在 O(1) 时间复杂度内完成这两种操作?


解题

LRU应该使用 哈希表双向链表 实现

对于get操作,首先判断key是否存在

  • 存在,那么返回该节点的值,找到该节点在双向链表中的位置,移到链表的头部
  • 不存在,返回 -1

对于 put 操作,首先判断key是否存在:

  • 如果key不存在,将输入的 key 和 value 创建一个新节点,添加到双向链表的头部,并且添加到哈希表中。判断双向链表长度是否超出要求,如果超出了,删除双向链表尾部的节点。

对于双向链表,在头部和尾部分别定义一个额外的节点,从而在删除和添加时避免考虑前后节点是否为空。

定义双向链表

class DuLNode:
	def __init__(self,key==0,value=0):
		self.key=key
		self.value=value
		self.prev=None
		self.next=None

LRU部分

class LRUCache:

    def __init__(self,capacity):
        self.cache=dict()
        self.capacity=capacity
        #额外的空节点 head 和 tail
        self.head=DuLNode()
        self.tail=DuLNode()
        self.head.next=self.tail
        self.tail.prev=self.head
        self.size=0
    
    def get(self,key:int):
        if key not in self.cache:
            return -1
        node=self.cache[key]
        self.moveToHead(node)
        return node.value
    
    def put(self,key:int,value:int):
        if key not in self.cache:
            node=DuLNode(key,value) #创建新节点
            self.cache[key]=node #添加到哈希表
            self.addToHead(node)
            self.size+=1
            if self.size>self.capacity:#如果超出长度
                rem=self.removeTail()#删除双向链表尾部元素
                self.cache.pop(rem.key)#删除哈希表中对应节点
                self.size-=1
        else:
            node=self.cache[key]
            node.value=value
            self.moveToHead(node)

    def addToHead(self,node):
        node.prev=self.head
        node.next=self.head.next
        self.head.next.prev=node
        self.head.next=node
    
    def moveToHead(self,node):
        self.removeNode(node)
        self.addToHead(node)

    def removeNode(self,node):
        node.next.prev=node.prev
        node.prev.next=node.next

    def removeTail(self):
        node=self.tail.prev
        self.removeNode(node)
        return node

题148.排序链表

题意

给定链表的头节点 head,将链表按照升序排列后返回。

进阶

  • 你可以在 O(n log n) 时间复杂度和常数级空间复杂度下,对链表进行排序吗?

解题

作为一道排序题,当看到进阶的时间复杂度要求时,我们就能想到那几种排序方法,首先可以用快速排序来解题,即每次将数组分成两段,分别排序,而后合并。

快速排序

对于本题,可以把每一段链表的 head 的节点值作为基准数,把链表分成 小于、等于、大于 基准数的三段,而后合并。

def sortList(self,head:ListNode)->ListNode:
	if not head:
		return head
	#分成左中右三段
	l,m,r=None,None,None
	cur=head
	while cur:
		tmp,cur=cur,cur.next
		if tmp.val<head.val:
			tmp.next=l
			l=tmp
		elif tmp.val>head.val:
			tmp.next=r
			r=tmp
		else:
			tmp.next=m
			m=tmp
	l=self.sortList(l)
	r=self.sortList(r)
	#左中右合并
	cur=res=ListNode(None)
	for c in [l,m,r]:
		while c:
			cur.next=c
			cur=cur.next
			c=c.next
			
	return res.next

时间复杂度达到了进阶的要求,但提交后还是超时了。

尝试第二种方法:归并排序

归并排序

归并排序的思想和快排类似,也是采用了分治的方法,从而达到进阶的时间复杂度要求,具体的做法:

  • 用快慢指针找到链表的中间节点,并且从当中切断,逐层切割
  • 将左右两段合并为一个升序链表,然后逐层归并,最终合一
def sortList(self,head:ListNode)->ListNode:
	if not head or not head.next:
		return head
	slow,fast=head,head.next
	#从当中切断
	while fast and fast.next:
		slow,fast=slow.next,fast.next.next
	mid,slow.next=slow.next,None
	
	left=self.sortList(head)
	right=self.sortList(mid)
	
	cur=res=ListNode(None)
	while left and right:
		if left.val<right.val:
			cur,left=left,left.next
		else:
			cur,right=right,right.next
		cur=cur.next
	
	cur.next = left if left else right
	return res.next

题155.最小栈

题意

设计一个支持 push ,pop ,top 操作,并能在常数时间内检索到最小元素的栈。

  • push(x) —— 将元素 x 推入栈中。
  • pop() —— 删除栈顶的元素。
  • top() —— 获取栈顶元素。
  • getMin() —— 检索栈中的最小元素。

解题

参考了官方题解,解题的方式是用一个辅助栈,这个栈有以下特点:

  • 和原栈同步进行入栈,出栈操作
  • 长度和原栈一样
  • 栈顶元素为原栈的最小值
  1. 入栈,原栈直接入栈,辅助栈对本栈顶的元素和入栈值进行比较,将更小值入栈,这样可以保证:
    • 栈顶元素为原栈的最小值
      -辅助栈长度和原栈一样
def push(self, x: int) -> None:
	self.stack.append(x)
	self.min_stack.append(min(x,self.min_stack[-1]))
  1. 出栈,假如原栈出的1是最小值,辅助栈出的则是同样的值,保证辅助栈的栈顶是新的最小值
def pop(self) -> None:
	self.stack.pop()
	self.min_stack.pop()
  1. 返回栈顶和最小值
def top(self) -> int:
	return self.stack[-1]

def getMin(self) -> int:
	return self.min_stack[-1]

另外一种思路,我觉得比较精彩,思路其实和上面一样,但不使用额外的栈 ,改为把原栈的元素改为二元元组。第一个值是原值,第二个值为当前栈内最小值。

  1. 入栈
def push(self,x):
	if not self.stack:
		self.stack.append((x,x))
	else:
		self.stack.append(x,min(self.stack[-1][1],x))
  1. 出栈直接pop

  2. 返回最小值:

def getMin(self):
	return self.stack[-1][1]
  1. 返回栈顶
def top(self):
	return self.stack[-1][0]
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值