题目描述
运用你所掌握的数据结构,设计和实现一个 LRU (最近最少使用) 缓存机制。它应该支持以下操作: 获取数据 get 和 写入数据 put 。
获取数据 get(key) - 如果密钥 (key) 存在于缓存中,则获取密钥的值(总是正数),否则返回 -1。
写入数据 put(key, value) - 如果密钥不存在,则写入其数据值。当缓存容量达到上限时,它应该在写入新数据之前删除最近最少使用的数据值,从而为新的数据值留出空间。
进阶:
你是否可以在 O(1) 时间复杂度内完成这两种操作?
示例:
LRUCache cache = new LRUCache( 2 /* 缓存容量 */ );
cache.put(1, 1);
cache.put(2, 2);
cache.get(1); // 返回 1
cache.put(3, 3); // 该操作会使得密钥 2 作废
cache.get(2); // 返回 -1 (未找到)
cache.put(4, 4); // 该操作会使得密钥 1 作废
cache.get(1); // 返回 -1 (未找到)
cache.get(3); // 返回 3
cache.get(4); // 返回 4
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/lru-cache
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
分析
设计LRU缓存机制我们一般可以想到使用Java里面现成的LinkedHashMap数据结构,LinkedHashMap继承自HashMap,具有和HashMap一样的快速查找特性,同时内部维护了一个双向链表,用来维护插入顺序或LRU顺序。而这就是题目所要求的吧。
具体实现:
- 可以设定最大缓存空间 为capacity;
- 使用 LinkedHashMap 的构造函数将 accessOrder 设置为 true,开启 LRU 顺序,一般默认为false,属于插入顺序;
- 覆盖 removeEldestEntry() 方法实现,在节点多于 capacity 就会将最近最久未使用的数据移除。
具体代码
package thread;
import java.util.LinkedHashMap;
import java.util.Map;
public class LRUCache extends LinkedHashMap<Integer, Integer> {
private Map<Integer, Integer> map;
public LRUCache(int capacity) {
map = new LinkedHashMap<Integer, Integer>(capacity, 0.75f, true){
protected boolean removeEldestEntry(Map.Entry eldest) {
return size() > capacity;
}
};
}
public int get(int key) {
return map.getOrDefault(key, -1);
}
public void put(int key, int value) {
map.put(key, value);
}
}
class LRUCache {
private int cap;
private Map<Integer, Integer> map = new LinkedHashMap<>();
public LRUCache(int capacity) {
this.cap = capacity;
}
public int get(int key) {
if(map.keySet().contains(key)) {
int value = map.get(key);
map.remove(key);
map.put(key, value);
return value;
}
return -1;
}
public void put(int key, int value) {
if(map.keySet().contains(key)) {
map.remove(key);
} else if(map.size() == cap) {
Iterator<Map.Entry<Integer, Integer>> iterator = map.entrySet().iterator();
iterator.next();
iterator.remove();
}
map.put(key, value);
}
}
/**
* Your LRUCache object will be instantiated and called as such:
* LRUCache obj = new LRUCache(capacity);
* int param_1 = obj.get(key);
* obj.put(key,value);
*/
搜狗研发第一题
搜狗当时一共就三道编程题,我也就只看了第一题。
第一题要求也简单,就是写LRU,写一个给定大小的LRU,然后不断往里面put键值对,键为字符串类型,值为整型,同时输出每次被淘汰的键值对。
package Algorithm;
import java.util.*;
public class Sougou {
static class Node {
String str;
int num;
int time;
public Node(String str, int num, int time) {
this.str = str;
this.num = num;
this.time = time;
}
}
static class MyComparator implements Comparator<Node> {
@Override
public int compare(Node a, Node b) {
return a.time < b.time ? -1 : 1;
}
}
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
int len = input.nextInt();
Node[] list = new Node[len];
int size = 0;
int time = 0;
HashMap<String, Integer> map = new HashMap<>();
while(input.hasNext()) {
String s = input.next();
int num = input.nextInt();
if(map.containsKey(s)) {
if(num > list[map.get(s)].num) {
list[map.get(s)].num = num;
list[map.get(s)].time = time;
}
} else {
if(size < len) {
list[size] = new Node(s, num, time);
map.put(s, size);
size++;
} else {
Comparator<Node> cmp = new MyComparator();
Arrays.sort(list, cmp);
map.remove(list[0].str);
System.out.println(list[0].str + " " + list[0].num);
list[0] = new Node(s, num, time);
map.put(s, 0);
for(int i = 1; i < len; i++) {
map.put(list[i].str, i);
}
}
}
time++;
}
}
}
当时找了个cpp写的lru,改了下交上去,只过了60%…后来把所有的int改成long long 再交一次,过了90%…不知道还有什么地方没考虑到
#include<iostream>
#include<vector>
#include<map>
using namespace std;
typedef long long ll;
class LRUCache
{
private:
ll capacity;
ll capacity_cur;
typedef struct ListNode
{
string key;
ll value;
struct ListNode* next;
struct ListNode* pre;
ListNode(string k , ll v):key(k),value(v),next(NULL),pre(NULL) {}
}ListNode;
ListNode *head;
typedef struct Value
{
ll val;
ListNode *p;
Value(ll _v,ListNode *pp):val(_v),p(pp){}
Value() {} //if this constructor is not defined,there will be wrong
}tValue;
map< string,tValue > mkv;
map< string,tValue > :: iterator it;
public:
LRUCache(ll capacity)
{
this->capacity = capacity;
head = new ListNode("0",0);
capacity_cur = 0;
}
ll get(string key)
{
if( is_exist(key) )
{
//get down the loc node
ListNode *loc = mkv[key].p;
loc->pre->next = loc->next;
loc->next->pre = loc->pre;
//insert into the front of the head
loc->next = head->next;
loc->pre = head;
head->next = loc;
loc->next->pre = loc;
return mkv[key].val;
}
else
{
return -1;
}
}
string temp;
ll tempVal;
void set(string key , ll value)
{
if( is_exist(key) )
{
//change the value in map and the list
mkv[key].val = value;
ListNode *q = mkv[key].p;
q->value = value;
//get the node and insert into the head of the list
q->pre->next = q->next;
q->next->pre = q->pre;
q->next = head->next;
q->pre = head;
head->next->pre = q;
head->next = q;
return ;
}
ListNode *tmp = new ListNode(key,value);
if(capacity_cur<capacity)
{
if(head->next==NULL) //the list is empty
{
head->next = tmp ;
head->pre = tmp;
tmp->next = head;
tmp->pre = head;
tValue tv(value,tmp);
mkv[key] = tv;
++capacity_cur;
}
else //insert the tmp into the front of the list
{
tmp->next = head->next;
tmp->pre = head;
head->next->pre = tmp;
head->next = tmp;
tValue tv(value,tmp);
mkv[key] = tv;
++capacity_cur;
}
}
else
{
//get rid of the lru node
ListNode *tail = head->pre;
head->pre = tail->pre;
tail->pre->next = head;
temp = tail->key;
tempVal = tail->value;
cout << temp << " " << tempVal << endl;
mkv.erase(tail->key);
delete tail;
//insert into the new node
tmp->next = head->next;
tmp->pre = head;
head->next->pre = tmp;
head->next = tmp;
tValue tv(value,tmp);
mkv[key] = tv;
}
}
bool is_exist(string key)
{
return ( mkv.find(key) != mkv.end() );
}
void print()
{
ListNode *p = head->next;
while(p!=head)
{
cout<<"key = "<<p->key<<" Value = "<<p->value<<endl;
p = p->next;
}
cout<<endl;
}
};
int main()
{
ll n, val;
scanf("%lld", &n);
string s;
LRUCache lru1(n);
while(cin >> s,
cin >> val) {
lru1.set(s, val);
}
return 0;
}