题目:https://leetcode.com/problems/lru-cache/
大学课本在讲操作系统的时候提及LRU可基于双向链表以及map来实现: 其中双向链表用于调整优先级,根据LRU规则淘汰对象; map主要用于快速查询。
将题目分解:
- get 操作涉及优先级调整
- set 操作涉及优先级调整以及淘汰操作
将题目转化为实现head()以及evict()两个函数;
- evict 淘汰队尾,有两种情况 1)队尾前面无节点,即:又是队首又是队尾 2)前面有节点
- head 将操作的节点放到队首,如果已经位于队首则无需操作: 1)这个元素之前已经存在于队列中 2)这个元素是新的
package org.bull.leetcode.alg;
import java.util.HashMap;
import java.util.Map;
/**
* Created by bull on 16/5/5.
* <p>
* https://leetcode.com/problems/lru-cache/
* get时涉及优先级调整
* set时涉及优先级调整以及淘汰操作
* 将问题化简为:实现 head以及evict函数
* <p>
* evict其实就是淘汰队尾:有两种情况 1)队尾前面无节点,即:又是队首又是队尾 2)前面有节点
* head 就是将操作的节点放到队首,如果已经位于队首则无需操作: 1)这个元素之前已经存在于队列中 2)这个元素是新的
*/
public class LRUCache {
private int capacity;
/**
* 用来保存队首,优先级调整基本针对队首
*/
private Entry head;
/**
* 淘汰对象基本针对队尾
*/
private Entry tail;
private Map<Integer, Entry> container;
public LRUCache(int capacity) {
this.capacity = capacity;
container = new HashMap<>(capacity);
}
/**
* 获取对象,并调整优先级
*
* @param key
* @return
*/
public int get(int key) {
Entry entry = container.get(key);
if (entry == null) {
return -1;
}
head(entry, true);
return entry.getValue();
}
/**
* 设置对象,如果达到阈值,淘汰队尾对象
*
* @param key
* @param value
*/
public void set(int key, int value) {
if (container.get(key) == null) {
if (container.size() >= capacity) {
evict();
}
Entry entry = new Entry();
entry.setKey(key);
entry.setValue(value);
head(entry, false);
container.put(key, entry);
} else {
Entry entry = container.get(key);
entry.setValue(value);
head(entry, true);
}
}
/**
* 淘汰队尾
*/
public void evict() {
Integer tailKey = tail.getKey();
container.remove(tailKey);
//调整队尾
Entry before = tail.before;
if (before == null) {
head = null;
tail = null;
} else {
before.next = null;
tail.before = null;
tail = before;
}
}
/**
* 将优先级置顶
*
* @param entry
*/
public void head(Entry entry, boolean in) {
if (in) {
if (entry.before != null) {
entry.before.next = entry.next;
if (entry.next == null) {//队尾
tail = entry.before;
} else {
entry.next.before = entry.before;
}
//调整队首
entry.before = null;
head.before = entry;
entry.next = head;
head = entry;
}
} else {
if (container.size() > 0) {//已经有元素
entry.next = head;
head.before = entry;
head = entry;
} else { //特点是 head 和 tail 都不存在
head = entry;
tail = entry;
}
}
}
/**
* 双向链表结构体
*/
class Entry {
private int key;
private int value;
private Entry next;
private Entry before;
public int getValue() {
return value;
}
public void setValue(int value) {
this.value = value;
}
public Entry getNext() {
return next;
}
public void setNext(Entry next) {
this.next = next;
}
public Entry getBefore() {
return before;
}
public void setBefore(Entry before) {
this.before = before;
}
public int getKey() {
return key;
}
public void setKey(int key) {
this.key = key;
}
}
}
总结来说,解题首先思路要对,然后要分解问题,分解问题是要全面考虑,然后有耐心一步步的去实现即可。