设计LRU缓存结构
题目:
思路:
由于set和get方法的时间复杂度为O(1),这就代表着不好用循环,所以应该采用能一次性取出来的方式。如头尾这种方便存取,所以应该一边常用,一边不常用,整体来说,链表结构比较合适。
直接把每次操作的元素塞到链表最末端,这样最后一位就是最常用的,其次,还要想着如何便于一次性检验元素是否在链表中。
代码示例:
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.LinkedHashMap;
public class Solution {
public static void main(String[] args) {
int[][] operators = {{1, 1, 1}, {1, 2, 2}, {1, 3, 2}, {2, 1}, {1, 4, 4}, {2, 2}};
int k = 3;
int[] result = LRU(operators, k);
System.out.println(Arrays.toString(result));
}
/**
* lru design
*
* @param operators int整型二维数组 the ops
* @param k int整型 the k
* @return int整型一维数组
*/
public static int[] LRU(int[][] operators, int k) {
/**
* 为什么使用LinkedHashMap而不用HashMap?
* 因为使用HashMap,按照插入key的hashcode值进行数组排序的,插入排序,不保证稳定性。
* {1=1, 2=2, 3=2},这里的1=1,如果我先删除了再插入,它依旧是{1=1, 2=2, 3=2},而不是{2=2, 3=2, 1=1}
* 这样就达不到了这里想要的后插入的放在后面越前面的代表最不常用的效果了
* 此外LinkedHashMap是继承于HashMap,拥有同样的方法
*/
LinkedHashMap<Integer, Integer> map = new LinkedHashMap<Integer, Integer>();
//另一方面这里的数组是因为不知道数据的长度,所以采用不限制长度的数组,后面还要对应的转成int[]类型的数组用于输出
ArrayList<Integer> temp = new ArrayList<Integer>();
for (int[] op : operators) {
switch (op[0]) {
case 1:
//判断是否大于长度,是的话要将头结点的最不常用删除,然后再添加新的
if (map.size() > k - 1) {
Iterator iter = map.keySet().iterator();
map.remove(iter.next());
}
map.put(op[1], op[2]);
break;
case 2:
//使用HashMap这类数据有的检验key,判断数据是否存在
//如果存在先将数据取出,再删除,再重新插入,为什么要这么复杂?
//因为思路是复杂度为O(1),如果要排序的话不太合适,直接增删会好一点
if (map.containsKey(op[1])) {
int num = map.get(op[1]);
map.remove(op[1]);
map.put(op[1], num);
temp.add(num);
} else {
temp.add(-1);
}
break;
default:
System.out.println("未知参数");
}
}
int[] result = new int[temp.size()];
int i = 0;
for (int end : temp) {
result[i++] = end;
}
return result;
}
}