热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

Google面经,跪在LFU缓存,想了好几天终于爬起来了

描述LFU是一个著名的缓存算法对于容量为k的缓存,如果缓存已满,并且需要逐出其中的密钥,则最少使用的密钥将被踢出。实现LFU中的set和

描述

LFU 是一个著名的缓存算法
对于容量为 k 的缓存,如果缓存已满,并且需要逐出其中的密钥,则最少使用的密钥将被踢出。
实现 LFU 中的 set 和 get

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
 Input:

LFUCache(3)

set(2,2)

set(1,1)

get(2)

get(1)

get(2)

set(3,3)

set(4,4)

get(3)

get(2)

get(1)

get(4)



Output:

2

1

2

-1

2

1

4

在线评测地址

解题思路

了解 LFU 的基本算法,按照要求进行模拟即可,记录下每一个的出现频率,如果满了,选出频率最低的踢出

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
public class LFUCache {



    private final Map cache;

    private final LinkedHashSet[] frequencyList;

    private int lowestFrequency;

    private int maxFrequency;

    private final int maxCacheSize;



    // @param capacity, an integer

    public LFUCache(int capacity) {

        // Write your code here

        this.cache = new HashMap(capacity);

        this.frequencyList = new LinkedHashSet[capacity * 2];

        this.lowestFrequency = 0;

        this.maxFrequency = capacity * 2 - 1;

        this.maxCacheSize = capacity;

        initFrequencyList();

    }



    // @param key, an integer

    // @param value, an integer

    // @return nothing

    public void set(int key, int value) {

        // Write your code here

        CacheNode currentNode = cache.get(key);

        if (currentNode == null) {

            if (cache.size() == maxCacheSize) {

                doEviction();

            }

            LinkedHashSet nodes = frequencyList[0];

            currentNode = new CacheNode(key, value, 0);

            nodes.add(currentNode);

            cache.put(key, currentNode);

            lowestFrequency = 0;

        } else {

            currentNode.v = value;

        }

        addFrequency(currentNode);

    }



    public int get(int key) {

        // Write your code here

        CacheNode currentNode = cache.get(key);

        if (currentNode != null) {

            addFrequency(currentNode);

            return currentNode.v;

        } else {

            return -1;

        }

    }



    public void addFrequency(CacheNode currentNode) {

        int currentFrequency = currentNode.frequency;

        if (currentFrequency
            int nextFrequency = currentFrequency + 1;

            LinkedHashSet currentNodes = frequencyList[currentFrequency];

            LinkedHashSet newNodes = frequencyList[nextFrequency];

            moveToNextFrequency(currentNode, nextFrequency, currentNodes, newNodes);

            cache.put(currentNode.k, currentNode);

            if (lowestFrequency == currentFrequency && currentNodes.isEmpty()) {

                lowestFrequency = nextFrequency;

            }

        } else {

            // Hybrid with LRU: put most recently accessed ahead of others:

            LinkedHashSet nodes = frequencyList[currentFrequency];

            nodes.remove(currentNode);

            nodes.add(currentNode);

        }

    }



    public int remove(int key) {

        CacheNode currentNode = cache.remove(key);

        if (currentNode != null) {

            LinkedHashSet nodes = frequencyList[currentNode.frequency];

            nodes.remove(currentNode);

            if (lowestFrequency == currentNode.frequency) {

                findNextLowestFrequency();

            }

            return currentNode.v;

        } else {

            return -1;

        }

    }



    public int frequencyOf(int key) {

        CacheNode node = cache.get(key);

        if (node != null) {

            return node.frequency + 1;

        } else {

            return 0;

        }

    }



    public void clear() {

        for (int i = 0; i <= maxFrequency; i++) {

            frequencyList[i].clear();

        }

        cache.clear();

        lowestFrequency = 0;

    }



    public int size() {

        return cache.size();

    }



    public boolean isEmpty() {

        return this.cache.isEmpty();

    }



    public boolean containsKey(int key) {

        return this.cache.containsKey(key);

    }



    private void initFrequencyList() {

        for (int i = 0; i <= maxFrequency; i++) {

            frequencyList[i] = new LinkedHashSet();

        }

    }



    private void doEviction() {

        int currentlyDeleted = 0;

        double target = 1; // just one

        while (currentlyDeleted
            LinkedHashSet nodes = frequencyList[lowestFrequency];

            if (nodes.isEmpty()) {

                break;

            } else {

                Iterator it = nodes.iterator();

                while (it.hasNext() && currentlyDeleted++
                    CacheNode node = it.next();

                    it.remove();

                    cache.remove(node.k);

                }

                if (!it.hasNext()) {

                    findNextLowestFrequency();

                }

            }

        }

    }



    private void moveToNextFrequency(CacheNode currentNode, int nextFrequency,

                                     LinkedHashSet currentNodes,

                                     LinkedHashSet newNodes) {

        currentNodes.remove(currentNode);

        newNodes.add(currentNode);

        currentNode.frequency = nextFrequency;

    }



    private void findNextLowestFrequency() {

        while (lowestFrequency <= maxFrequency && frequencyList[lowestFrequency].isEmpty()) {

            lowestFrequency++;

        }

        if (lowestFrequency > maxFrequency) {

            lowestFrequency = 0;

        }

    }



    private class CacheNode {

        public final int k;

        public int v;

        public int frequency;



        public CacheNode(int k, int v, int frequency) {

            this.k = k;

            this.v = v;

            this.frequency = frequency;

        }

    }

}

更多题解参考


推荐阅读
  • JDK源码学习之HashTable(附带面试题)的学习笔记
    本文介绍了JDK源码学习之HashTable(附带面试题)的学习笔记,包括HashTable的定义、数据类型、与HashMap的关系和区别。文章提供了干货,并附带了其他相关主题的学习笔记。 ... [详细]
  • sklearn数据集库中的常用数据集类型介绍
    本文介绍了sklearn数据集库中常用的数据集类型,包括玩具数据集和样本生成器。其中详细介绍了波士顿房价数据集,包含了波士顿506处房屋的13种不同特征以及房屋价格,适用于回归任务。 ... [详细]
  • 欢乐的票圈重构之旅——RecyclerView的头尾布局增加
    项目重构的Git地址:https:github.comrazerdpFriendCircletreemain-dev项目同步更新的文集:http:www.jianshu.comno ... [详细]
  • 生成式对抗网络模型综述摘要生成式对抗网络模型(GAN)是基于深度学习的一种强大的生成模型,可以应用于计算机视觉、自然语言处理、半监督学习等重要领域。生成式对抗网络 ... [详细]
  • 云原生边缘计算之KubeEdge简介及功能特点
    本文介绍了云原生边缘计算中的KubeEdge系统,该系统是一个开源系统,用于将容器化应用程序编排功能扩展到Edge的主机。它基于Kubernetes构建,并为网络应用程序提供基础架构支持。同时,KubeEdge具有离线模式、基于Kubernetes的节点、群集、应用程序和设备管理、资源优化等特点。此外,KubeEdge还支持跨平台工作,在私有、公共和混合云中都可以运行。同时,KubeEdge还提供数据管理和数据分析管道引擎的支持。最后,本文还介绍了KubeEdge系统生成证书的方法。 ... [详细]
  • CSS3选择器的使用方法详解,提高Web开发效率和精准度
    本文详细介绍了CSS3新增的选择器方法,包括属性选择器的使用。通过CSS3选择器,可以提高Web开发的效率和精准度,使得查找元素更加方便和快捷。同时,本文还对属性选择器的各种用法进行了详细解释,并给出了相应的代码示例。通过学习本文,读者可以更好地掌握CSS3选择器的使用方法,提升自己的Web开发能力。 ... [详细]
  • Whatsthedifferencebetweento_aandto_ary?to_a和to_ary有什么区别? ... [详细]
  • Android系统源码分析Zygote和SystemServer启动过程详解
    本文详细解析了Android系统源码中Zygote和SystemServer的启动过程。首先介绍了系统framework层启动的内容,帮助理解四大组件的启动和管理过程。接着介绍了AMS、PMS等系统服务的作用和调用方式。然后详细分析了Zygote的启动过程,解释了Zygote在Android启动过程中的决定作用。最后通过时序图展示了整个过程。 ... [详细]
  • 如何自行分析定位SAP BSP错误
    The“BSPtag”Imentionedintheblogtitlemeansforexamplethetagchtmlb:configCelleratorbelowwhichi ... [详细]
  • 在Android开发中,使用Picasso库可以实现对网络图片的等比例缩放。本文介绍了使用Picasso库进行图片缩放的方法,并提供了具体的代码实现。通过获取图片的宽高,计算目标宽度和高度,并创建新图实现等比例缩放。 ... [详细]
  • 本文介绍了九度OnlineJudge中的1002题目“Grading”的解决方法。该题目要求设计一个公平的评分过程,将每个考题分配给3个独立的专家,如果他们的评分不一致,则需要请一位裁判做出最终决定。文章详细描述了评分规则,并给出了解决该问题的程序。 ... [详细]
  • JVM 学习总结(三)——对象存活判定算法的两种实现
    本文介绍了垃圾收集器在回收堆内存前确定对象存活的两种算法:引用计数算法和可达性分析算法。引用计数算法通过计数器判定对象是否存活,虽然简单高效,但无法解决循环引用的问题;可达性分析算法通过判断对象是否可达来确定存活对象,是主流的Java虚拟机内存管理算法。 ... [详细]
  • 本文详细介绍了Java中vector的使用方法和相关知识,包括vector类的功能、构造方法和使用注意事项。通过使用vector类,可以方便地实现动态数组的功能,并且可以随意插入不同类型的对象,进行查找、插入和删除操作。这篇文章对于需要频繁进行查找、插入和删除操作的情况下,使用vector类是一个很好的选择。 ... [详细]
  • [大整数乘法] java代码实现
    本文介绍了使用java代码实现大整数乘法的过程,同时也涉及到大整数加法和大整数减法的计算方法。通过分治算法来提高计算效率,并对算法的时间复杂度进行了研究。详细代码实现请参考文章链接。 ... [详细]
  • 模板引擎StringTemplate的使用方法和特点
    本文介绍了模板引擎StringTemplate的使用方法和特点,包括强制Model和View的分离、Lazy-Evaluation、Recursive enable等。同时,还介绍了StringTemplate语法中的属性和普通字符的使用方法,并提供了向模板填充属性的示例代码。 ... [详细]
author-avatar
戴劳力士_484
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有