LFU Cache:最不经常使用页置换算法

Design and implement a data structure for Least Frequently Used (LFU) 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 reaches its capacity, it should invalidate the least frequently used item before inserting a new item. For the purpose of this problem, when there is a tie (i.e., two or more keys that have the same frequency), the least recently used key would be evicted.

Follow up:
Could you do both operations in O(1) time complexity?

Example:

LFUCache cache = new LFUCache( 2 /* capacity */ );

cache.put(1, 1);
cache.put(2, 2);
cache.get(1);       // returns 1
cache.put(3, 3);    // evicts key 2
cache.get(2);       // returns -1 (not found)
cache.get(3);       // returns 3.
cache.put(4, 4);    // evicts key 1.
cache.get(1);       // returns -1 (not found)
cache.get(3);       // returns 3
cache.get(4);       // returns 4
思路:LFU,就是最不经常使用页置换算法。难点:

一:O(1)访问速度,所以要使用hash,形式是<key,val>

二:更新访问频率,而且也要O(1),所以也要使用hash,形式是<key,count>

三:无多余空间时,删除访问频率最低的元素,所以对于每个count也要记录下,形式是<count,linkededhashset>,因为linkedhashset有序,可以对应当访问次数相同时按先后次序剔除(即删除链表开头元素)

四:存在<key,old> -> <key,new>这种情况,所以除了更近=新键值对以外,也要讲访问频率更新


原理都明白,可真正写的时候真的是困难!!!


public class LFUCache {
	int min = -1;// 表示当前最小的访问频率等级
	HashMap<Integer, Integer> val = new HashMap<Integer, Integer>();// key,val
	HashMap<Integer, Integer> counts = new HashMap<Integer, Integer>();// key,counts
	HashMap<Integer, LinkedHashSet<Integer>> level = new HashMap<Integer, LinkedHashSet<Integer>>();// count,set
																									// 记录每个访问频率等级集下的key
	int size = 0;

	public LFUCache(int capacity) {
		this.size = capacity;
		level.put(1, new LinkedHashSet<Integer>());
		min = 1;//最小值的作用是为了当空间不足时,找到访问频率最低的那个集中最靠前(出现最早)的元素而设置
	}

	public int get(int key) {
		if (!val.containsKey(key)) {// key不存在,返回-1
			// System.out.println("key不存在");
			return -1;
		}
		int count = (counts.get(key) == null) ? 0 : counts.get(key);// 记录频率
		// System.out.println(count);
		int result = val.get(key);// 获取返回值
		counts.put(key, count + 1);// 记录下新访问频率
		level.get(count).remove(key);// 剔除原访问等级下,包含的该key
		if (!level.containsKey(count + 1)) {// 如果将要更新的访问等级还为未出现过,创建一个新的访问等级集
			level.put((count + 1), new LinkedHashSet<Integer>());
		}
		level.get((count + 1)).add(key);// 更新访问等级集中的key
		if (min == count && level.get(count).size() == 0)// 修改最小值
		{
			min++;
		}
		// System.out.println("get "+key+" :"+val);
		return result;
	}

	public void put(int key, int value) {
		if (size <= 0)
			return;// 没有空间
		if (val.containsKey(key)) {// 仅仅是更新值,包括空间未满与空间刚刚号重慢两种情况,仅需要更新val值与访问次数(相当于一次get)
			val.put(key, value);
			get(key);
			return;
		}
		if ((val.size() >= size))// 空间不足,先移除最近访问次数最低的元素
		{
			// System.out.println(min);
			int oldkey = level.get(min).iterator().next();
			// System.out.println("oldkey:"+oldkey);
			val.remove(oldkey);
			counts.remove(oldkey);
			level.get(min).remove(oldkey);
			// System.out.println("after remove ,val:"+val);
			// System.out.println("after remove ,count:"+counts);

		}
		// 添加新元素,此时或者一开始就有剩余空间,或者因为空间已满而清理出空间后有剩余空间
		val.put(key, value);
		counts.put(key, 1);
		level.get(1).add(key);
		min = 1;
		// System.out.println("put "+key+" :"+val);
	}
	    
	    public static void main(String[] args){
	    	StringBuilder sb = new StringBuilder();
	    	//["LFUCache","put","put","get","put","get","get","put","get","get","get"]
	    	//[[2],[1,1],[2,2],[1],[3,3],[2],[3],[4,4],[1],[3],[4]]
	    	
	    	/*
	    	LFUCache obj = new LFUCache(2);
	    	obj.put(1,1);
	    	obj.put(2,2);
	    	sb.append(obj.get(1));
	    	obj.put(3,3);
	    	sb.append(obj.get(2));
	    	sb.append(obj.get(3));
	    	obj.put(4,4);
	    	sb.append(obj.get(1));
	    	sb.append(obj.get(3));
	    	sb.append(obj.get(4));
	    	System.out.println(sb.toString());
	    	
	    	*/
	    	LFUCache obj = new LFUCache(0);
	    	obj.put(0,0);
	    	sb.append(obj.get(0));
	    	System.out.println(sb.toString());
	    }
}





  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值