前言
昨天参加了阿里云的笔试,笔试是单独给我发了一个链接,不像是统一的笔试,两个小时做两个题也是我没有想到的,最后还是没有做完。所以就想着来整理以下这两个题目,下面就开始了。
LRU缓存
题目
- 第一题:
- 实现一个 LRU 缓存,支持指定缓存大小,支持 get 和 put 操作。使用频率越低的数据放在越后面,若缓存满了,删除最后面的数据。(语言不限)
- 输入:操作序列,包括 get 和 put 操作。
- 输出:根据 get 操作返回对应的值,put 操作无输出。
- 要求:时间复杂度为 O(1)。需要考虑编程习惯,包括但不限于可读性、可维护性、命名规范、代码风格等。
分析
- 这个题是力扣第147题,如果我们要实现时间复杂度为O(1)的要求,而且要满足使用频率越低的数据放在最后,也就是说当我们put一个数据之后,首先需要查询这个数据是否存在,如果存在还需要把这个数据放到最前面,其次是get方法,也需要我们查找到一个数据,再返回。
- 我们能够想到的查询方法基本上不会有O(1)的存在,所以这里我们需要借助多个数据结构,比如用一个HashMap记录每一个节点的id和节点,用一个双向链表记录节点之间的相对位置。每次get节点,就用这个id来获取节点信息,可以直接在哈希映射(Hashmap)里面查找,这个复杂度为O(1),找到之后获取对应的节点,然后输出节点的value。
- 在实现get功能的时候,我们也要知道怎么定义一个节点,也就是说节点类里面有什么信息,就像定义二叉树的节点一样,双向链表的节点如何定义呢?那就看以下代码:
class DlinkedNode{
int key;
int value;
DlinkedNode prev;
DlinkedNode next;
DlinkedNode(){
}
DlinkedNode(int key_,int value_){
key = key_;
value = value_;
}
}
由此能够构建一个双向链表。
代码
public class LRUCache {
// 正是因为链表节点有向前和向后的指针,所以当我们在HashMap中找到他的时候,我们同样能够在双向链表中找到他的位置
class DLinkedNode {
int key;
int value;
DLinkedNode prev;
DLinkedNode next;
public DLinkedNode() {
}
public DLinkedNode(int _key, int _value) {
key = _key; value = _value;}
}
// 用HashMap来存储节点和id, 一个LRUCache就包括以下内容,首先有一个HashMap
// 其次就是双向链表所需要的头指针与尾指针,再就是Cache的容量和目前已有的数据个数
private Map<Integer, DLinkedNode> cache = new HashMap<Integer, DLinkedNode>();
private int size;
private int capacity;
private DLinkedNode head, tail;
//初始化的时候就得将各个变量都初始化,而且形成双向链表
public LRUCache(int capacity) {
this.size = 0;
this.capacity = capacity;
// 使用伪头部和伪尾部节点
head = new DLinkedNode();
tail = new DLinkedNode();
head.next = tail;
tail.prev = head;
}
public int get(int key) {
DLinkedNode node = cache.get(key);
if (node == null) {

最低0.47元/天 解锁文章

1504

被折叠的 条评论
为什么被折叠?



