146. LRU缓存机制

题目描述

运用你所掌握的数据结构,设计和实现一个 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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值