今天简单记录一下,利用Scala解答的一道LRU题目,原题为LeetCode的第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

解答思路

这道题里,可以立即想到的是借助HashMap以及双向链表构建,更具体的分析可看LeetCode官方分析,在此不做赘述。

我的代码

对于Scala,由于其可以交叉使用Java的数据结构,因此在HashMap的构建部分,我也尝试了分别利用Scala自带的mutable.HashMap,以及Java当中的HashMap进行了比较,具体代码如下:

Scala的mutable.HashMap

import scala.collection.mutable.HashMap

class Node(var _key: Int, var _value: Int) {
var key = _key
var value = _value
var prev: Node = _
var next: Node = _
} class DoubleLinked() {
var head: Node = new Node(-1, -1)
var tail: Node = new Node(-1, -1)
head.next = tail
tail.prev = head def addNode(node: Node): Unit = {
head.next.prev = node
node.next = head.next
head.next = node
node.prev = head
} def updateTail(node: Node): Unit = {
tail.prev = node
node.next = tail
}
} class LRUCache(_capacity: Int) {
var cache: HashMap[Int, Node] = new HashMap[Int, Node]()
var dLinked = new DoubleLinked()
val capacity: Int = _capacity def get(key: Int): Int = {
if (!cache.contains(key)) {
return -1
}
updateSurroundings(cache(key))
dLinked.addNode(cache(key))
cache(key).value
} def put(key: Int, value: Int) {
if (cache.contains(key)) {
val node = cache(key)
node.value = value
updateSurroundings(node)
dLinked.addNode(node)
} else {
val node = new Node(key, value)
dLinked.addNode(node)
if (dLinked.tail.prev == dLinked.head) {
dLinked.tail.prev=node
node.next=dLinked.tail
}
cache.put(key,node) if(cache.size>capacity){
cache.remove(dLinked.tail.prev.key)
dLinked.updateTail(dLinked.tail.prev.prev)
dLinked.tail
}
}
} def updateSurroundings(node: Node): Unit = {
if (node.next == dLinked.tail) {
dLinked.tail.prev = node.prev
} node.prev.next = node.next
node.next.prev = node.prev
}
}

经提交测试,在LeetCode提交测试结果中,执行用时1628ms,占用内存82.9M

Java的HashMap

import java.util.HashMap

class Node(var _key: Int, var _value: Int) {
var key = _key
var value = _value
var prev: Node = _
var next: Node = _
} class DoubleLinked() {
var head: Node = new Node(-1, -1)
var tail: Node = new Node(-1, -1)
head.next = tail
tail.prev = head def addNode(node: Node): Unit = {
head.next.prev = node
node.next = head.next
head.next = node
node.prev = head
} def updateTail(node: Node): Unit = {
tail.prev = node
node.next = tail
}
} class LRUCache(_capacity: Int) {
var cache: HashMap[Int, Node] = new HashMap[Int, Node]()
var dLinked = new DoubleLinked()
val capacity: Int = _capacity def get(key: Int): Int = {
var node:Node = cache.get(key)
if (node == null) {
return -1
}
updateSurroundings(node)
dLinked.addNode(node)
node.value
} def put(key: Int, value: Int) {
if (cache.get(key)!=null) {
val node = cache.get(key)
node.value = value
updateSurroundings(node)
dLinked.addNode(node)
} else {
val node = new Node(key, value)
dLinked.addNode(node)
if (dLinked.tail.prev == dLinked.head) {
dLinked.tail.prev=node
node.next=dLinked.tail
}
cache.put(key,node) if(cache.size>capacity){
cache.remove(dLinked.tail.prev.key)
dLinked.updateTail(dLinked.tail.prev.prev)
dLinked.tail
}
}
} def updateSurroundings(node: Node): Unit = {
if (node.next == dLinked.tail) {
dLinked.tail.prev = node.prev
} node.prev.next = node.next
node.next.prev = node.prev
}
}

经提交测试,在LeetCode提交测试结果中,执行用时1456ms,占用内存83.9M

从上述的数据来看,两者运行时的占用内存相近,但是在速度上,使用Java的HashMap版本的代码,运行相对更快,所以有个猜想:如果在Scala代码中,直接使用Java原有的数据结构,是不是也同样会提高Scala代码的运行速度?

希望Scala方面的专家可以解答一下。

写一个LRU算法的记录的更多相关文章

  1. 面试题目:手写一个LRU算法实现

    一.常见的内存淘汰算法 FIFO  先进先出 在这种淘汰算法中,先进⼊缓存的会先被淘汰 命中率很低 LRU Least recently used,最近最少使⽤get 根据数据的历史访问记录来进⾏淘汰 ...

  2. 搞定redis面试--Redis的过期策略?手写一个LRU?

    1 面试题 Redis的过期策略都有哪些?内存淘汰机制都有哪些?手写一下LRU代码实现? 2 考点分析 1)我往redis里写的数据怎么没了? 我们生产环境的redis怎么经常会丢掉一些数据?写进去了 ...

  3. 【redis前传】自己手写一个LRU策略 | redis淘汰策略

    title: 自己手写一个LRU策略 date: 2021-06-18 12:00:30 tags: - [redis] - [lru] categories: - [redis] permalink ...

  4. 手写一个LRU工具类

    LRU概述 LRU算法,即最近最少使用算法.其使用场景非常广泛,像我们日常用的手机的后台应用展示,软件的复制粘贴板等. 本文将基于算法思想手写一个具有LRU算法功能的Java工具类. 结构设计 在插入 ...

  5. JS 实现一个 LRU 算法

    LRU 是 Least Recently Used 的缩写,即最近最少使用,是一种常用的页面置换算法,选择内存中最近最久未使用的页面予以淘汰. 可用的 NodeJS 库见node-lru-cache ...

  6. 动手写一个LRU缓存

    前言 LRU 是 Least Recently Used 的简写,字面意思则是最近最少使用. 通常用于缓存的淘汰策略实现,由于缓存的内存非常宝贵,所以需要根据某种规则来剔除数据保证内存不被占满. 在r ...

  7. python学习(5)写一个二分算法的程序

    把之前学习的做一个小结.之前看二分查找法,只能是似而非地看懂大概.现在用这么多天的知识积累已经可以自己写了. 而且在算法书的基础上,把需要找的数字做一个人机互动操作. 另外,初步接触到了 __name ...

  8. 4.redis 的过期策略都有哪些?内存淘汰机制都有哪些?手写一下 LRU 代码实现?

    作者:中华石杉 面试题 redis 的过期策略都有哪些?内存淘汰机制都有哪些?手写一下 LRU 代码实现? 面试官心理分析 如果你连这个问题都不知道,上来就懵了,回答不出来,那线上你写代码的时候,想当 ...

  9. GuavaCache学习笔记一:自定义LRU算法的缓存实现

    前言 今天在看GuavaCache缓存相关的源码,这里想到先自己手动实现一个LRU算法.于是乎便想到LinkedHashMap和LinkedList+HashMap, 这里仅仅是作为简单的复习一下. ...

随机推荐

  1. 你所不知道的Python | 字符串连接的秘密

    字符串连接,就是将2个或以上的字符串合并成一个,看上去连接字符串是一个非常基础的小问题,但是在Python中,我们可以用多种方式实现字符串的连接,稍有不慎就有可能因为选择不当而给程序带来性能损失. 方 ...

  2. C++如何求程序运行时间

    C++中常用clock()函数求运行时间,返回值类型为clock_t,返回值是程序运行到本次调用clock()函数经过的clock数,头文件为<time.h>. 用法: 1.求开始时间s= ...

  3. 负载均衡服务之HAProxy https配置、四层负载均衡以及访问控制

    前文我们聊了下haproxy的访问控制ACL的配置,回顾请参考https://www.cnblogs.com/qiuhom-1874/p/12817773.html:今天我们来聊一聊haproxy的h ...

  4. 洛谷 P 4180 次小生成树

    题目描述 小C最近学了很多最小生成树的算法,Prim算法.Kurskal算法.消圈算法等等.正当小C洋洋得意之时,小P又来泼小C冷水了.小P说,让小C求出一个无向图的次小生成树,而且这个次小生成树还得 ...

  5. 经过踩坑,搭建成功的Appium自动化测试环境

    因为最近本人准备搞app自动化,所以就搭建环境过程记录下来(主要踩过好几个坑) 期间有点烦躁,后面调整了下心态还是成功弄好了. 一.Appium环境搭建准备软件 所需要到的软件如下: 1.安装JDK1 ...

  6. 编译原理-第四章 语法分析-4.7 规范的LR分析

    规范的LR分析 一.规范LR(l)项 二.规范LR(l)项集族 1.构建项目集 2.例 三.规范LR(1)语法分析表 1.构造 2.例1 3.例2 四.LALR语法分析表 1.重要性 2.特点 3.构 ...

  7. FPGA-中值滤波(1)代码

    module shift_ram_3_8bit #( parameter Ram_Length = 'd640 ) ( clken, clock, shiftin, shiftout, taps0x, ...

  8. Linux暂时提升非root用户的权限

    sudo 用于提升非root用户的某些命令执行权限 1,使用root用户,复制vim /etc/sudoers 文件的第91行修改为,想提升的用户名称 root ALL=(ALL) ALL admin ...

  9. 加速你的网络!软路由构建 去AD+国内域名加速解析+抗污染+速度优选 与PSW无缝集成 综合方案

    本方案利用OpenWrt搭建4级DNS,实现 去AD + 国内域名加速解析 + 抗污染(域名解析按地区分流)+ 访问速度优选. 方案涉及部分软件配置细节可以参照之前博文:https://www.cnb ...

  10. 常用中文分词工具分词&词性标注简单应用(jieba、pyhanlp、pkuseg、foolnltk、thulac、snownlp、nlpir)

    1.jieba分词&词性标注 import jieba import jieba.posseg as posseg txt1 =''' 文本一: 人民网华盛顿3月28日电(记者郑琪)据美国约翰 ...