lintcode算法题:LFUCache

ε祈祈猫儿з 提交于 2021-02-18 16:57:38

问题描述:实现LFU中的get和set(LFU:least frequently used ,即最不经常使用页置换算法,要求在页置换时置换引用计数最小的页,因为经常使用的页应该有一个较大的引用次数。但是有些页在开始时使用次数很多,但以后就不再使用,这类页将会长时间留在内存中,因此可以将引用计数寄存器定时右移一位,形成指数衰减的平均使用次数。--百度 -_-|||)

样例:缓存大小为3(capacity =3)

set(2,2)
set(1,1)
get(2)
>> 2
get(1)
>> 1
get(2)
>> 2
set(3,3)
set(4,4)
get(3)
>> -1
get(2)
>> 2
get(1)
>> 1
get(4)
>> 4

我的实现思路:

1.Map用来存储缓存

2.使用双向链表来标记移除顺序。

   将使用次数最少元素中的访问时间最早的哪一个放到链表尾部,作为下一个删除对象。

   每次set(新加入)数据时,检查map大小等于capacity值时,从map中删除数据(根据链表尾部数据的key),并将链表尾部替换为新数据。

   每次set(更新)数据时,直接更新map中的数据,并跟新数据的时间标记和使用频次

   然后,将set的数据在链表中向前重新排序(当链表前一元素的使用频次低于本数据或者频次相等但是时间标记早于本元素时,将此两元素交换位置)

  每次get数据时,更新数据的使用频次和时间标记,并在此执行链表中该元素的重新排序

上代码(提交给lintcode后,发现还有其他的更优的实现。。。还没有细看)

public class LFUCache {
    /*
     * @param capacity: An integer
     */
    private Map<Integer, CacheItem> map = new HashMap<>();
    private CacheItem footNode;
    private int capacity;
    private long cnt=Long.MIN_VALUE;

    public LFUCache(int capacity) {
        // do intialization if necessary
        this.capacity=capacity;
    }

    /*
     * @param key: An integer
     * @param value: An integer
     * @return: nothing
     */
    public void set(int key, int value) {
        // write your code here
        CacheItem item;
        if(map.containsKey(key)) {
            item=map.get(key);
            item.value=value;
            item.update_time=cnt++;
            item.frecquece++;
        } else {
            CacheItem newItem = new CacheItem();
            newItem.value=value;
            newItem.key=key;
            newItem.update_time = cnt++;
            if(map.size() == capacity){
                map.remove(footNode.key);
                footNode = footNode.before;
            }
            newItem.before=footNode;
            if(footNode != null) {
                footNode.next = newItem;
            }
            footNode=newItem;
            item=newItem;
        }
        resortBefore(item);
        map.put(key,item);
    }

    /*
     * @param key: An integer
     * @return: An integer
     */
    public int get(int key) {
        // write your code here
        if(!map.containsKey(key)) return -1;
        CacheItem item = map.get(key);
        int value=item.value;
        item.frecquece++;
        item.update_time=cnt++;
        resortBefore(item);
        return value;
    }

    private void resortBefore(CacheItem item){
        if(item.before != null && (item.frecquece > item.before.frecquece || (item.frecquece == item.before.frecquece && item.update_time >= item.before.update_time))){
            CacheItem swap = item.before;
            CacheItem swapbefore = item.before.before;
            CacheItem swapafter = item.next;
            if(swapbefore != null) {
                swapbefore.next = item;
            }
            item.before = swapbefore;
            swap.before = item;
            swap.next = swapafter;
            if(swapafter != null) {
                swapafter.before=swap;
            }else{
                footNode=swap;
            }
            item.next = swap;
            resortBefore(item);
        }
    }


    private static class CacheItem {
        CacheItem before;
        CacheItem next;
        int key;
        int value;
        long update_time;
        int frecquece;
    }
}

代码比较简单,没有写注释。。。(这题在lintcode中居然是【困难】级,很多【简单】级的反而感觉无法下手 -_-|||)

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!