problem
Design and implement a data structure for Least Recently Used (LRU) cache. It should support the following operations: get and put.
get(key) - Get the value (will always be positive) of the key if the key exists in the cache, otherwise return -1.
put(key, value) - Set or insert the value if the key is not already present. When the cache reached its capacity, it should invalidate the least recently used item before inserting a new item.
The cache is initialized with a positive capacity.
solution
思考过程
这个就是操作系统中对进程的一种调度算法,不过这里时简化版本,行的
最近最少使用就是当capacity 满了过后,清理掉的数据应该是最没有被使用过的
其中get操作就更新了被get的数据的时间长度变成了最新被使用的
既然这样的话,两个想法:(最好不要用背后的库,这里最好自己设计才能体现一种最原始的思想吧
第一,用一种数据结构,索引为第一个或是最后一个的就是最新最近使用的,get过后,都要把相应的数据放到相应的位置表明是最新的,达到容量过后,就删掉相反的端的位置
用hash表来存储,因为key的唯一性和便于查找,用链表来更改数据的位置 ,底层的实现。
每次在插入的时候都要遍历链表,
很不方便呀,再开辟一个空间存key值,针对python和java,应该是不一样的
在数组里面实现链表,而且也要方便调换,我的python语法功底不行呀
看了LeetCode大佬的解题,机智呀,,你要找到目前链表的前后结构所在,双向链表
原来put已有的key值,就是更新原理啊的值,也算对这个值的访问,要放到头队列
第二,给每一个数据来一个时间索引,细想好像不太好,每次都要调整
方法
代码
Java
class LRUCache {
private class TreeNode{
int key=0;
int value=0;
TreeNode pre=null;
TreeNode next=null;
public TreeNode(){
}
}
private int size = 0;
private int capacity = 0;
private TreeNode head = new TreeNode();
HashMap<Integer, TreeNode> hashmap = new HashMap<>();
public LRUCache(int capacity) {
this.capacity = capacity;
this.head.next = this.head;
this.head.pre = this.head;
}
public void putanewone(TreeNode node){
node.next=head.next;
node.pre=head;
head.next=node;
node.next.pre=node;
}
public void movetofirst(TreeNode node){
node.pre.next=node.next;
node.next.pre=node.pre;
putanewone(node);
}
public int get(int key) {
if (hashmap.containsKey(key)){
movetofirst(hashmap.get(key));
return hashmap.get(key).value;
}
return -1;
}
public void put(int key, int value) {
if (hashmap.containsKey(key)){
hashmap.get(key).value=value;
movetofirst(hashmap.get(key));
}
else if(size<capacity){
TreeNode node=new TreeNode();
node.key=key;
node.value=value;
hashmap.put(key,node);
size++;
putanewone(node);
}
else{
head.key=key;
head.value=value;
hashmap.put(key,head);
head=head.pre;
hashmap.remove(head.key);
}
}
}
python
class Node:
def __init__(self, value=None):
self.value = value
# 以为这个key可以不用的,但是后面为了节省开销,不得不用哎
self.key = None
self.pre = None
self.next = None
class LRUCache:
def __init__(self, capacity: int):
self.hashmap = {}
self.size = 0
self.capacity = capacity
# 构成一个环,而不用尾节点
self.head = Node()
self.head.pre = self.head
self.head.next = self.head
def putanewone(self, node) -> None:
node.next = self.head.next
node.pre = self.head
node.next.pre = node
self.head.next = node
def movetofirst(self, node) -> None:
# 要把原来的位置给衔接上
node.pre.next = node.next
node.next.pre = node.pre
self.putanewone(node)
def get(self, key: int) -> int:
if key in self.hashmap:
# 让head的next指向该节点
self.movetofirst(self.hashmap[key])
return self.hashmap[key].value
return -1
def put(self, key: int, value: int) -> None:
if key in self.hashmap:
self.hashmap[key].value = value
# 传入节点的位置好更改
# 让head的next指向该节点
self.movetofirst(self.hashmap[key])
# 如果容量满了,可不可以直接替换掉尾巴那个,而不创建新的node呢?
elif self.size < self.capacity:
node = Node(value)
node.key=key
self.hashmap[key] = node
# size的容量加1
self.size += 1
self.putanewone(node)
else:
# 你也许可以直接把头节点的位置和尾节点位置调换,把新的值给head,别忘记更改原来的hashmap
self.head.key=key
self.head.value=value
self.hashmap[key]=self.head
self.head=self.head.pre
del self.hashmap[self.head.key]
总结
- hsahmap和双向链表的两种数据结构的结合使用可以很好的避免数组和链表的不足,完成在查找和增删的结合使用
- 代码果然是错一个字都不行呀,就是一个if和elif 的区别,我找代码的bug找了至少两小时╥﹏╥…
- 短时间内写出无bug的代码还是得多多练习,向来都是自己逻辑错误和敲代码手误