面试题30:
问题:
设计一个数据结构,使插入、删除和随机访问的时间复杂度是O(1)。
解决方案:
- 使用哈希表,可以让插入和删除的时间复杂度是O(1)。但是只使用哈希表,则不能等概率地返回其中的每个数值。
- 使用数组,可以等概率的返回每一个数值。将数值保存在数组中,然后用哈希表来存储数值在数组中所处的位置,哈希表的键为数值,值为数值在数组中所处的位置。
源代码:
class RandomizedSet {
HashMap<Integer, Integer> numToLocation;
List<Integer> nums;
//随机函数
Random random;
public RandomizedSet() {
numToLocation = new HashMap<>();
nums = new ArrayList<>();
random = new Random();
}
public boolean insert(int val) {
//如果哈希表中存在该值,不需要重复添加,则返回false。
if(numToLocation.containsKey(val)){
return false;
}
numToLocation.put(val,nums.size());
nums.add(val);
return true;
}
public boolean remove(int val) {
if(!(numToLocation.containsKey(val))){
return false;
}
//下标
int location = numToLocation.get(val);
//数组最后一位的值
int last = nums.get(nums.size() - 1);
//数组最后一位的值所在下标位置改为删除值的所在下标位置
numToLocation.put(last,location);
//删除值的所在下标位置的值替换为数组最后一位的值
nums.set(location,last);
numToLocation.remove(val);
nums.remove(nums.size() - 1);
return true;
}
public int getRandom() {
int result = random.nextInt(nums.size());
return nums.get(result);
}
}
面试题31:
问题:
- 设计实现缓存,使缓存的两个操作get(key)和put(key,value)的时间复杂度都是O(1)。
- 当进行put(key,value)操作时,缓存的容量满了,需要先缓存中最长时间没有被使用过的元素。
解决方案:
- 使用哈希表,哈希表的的两个操作get(key)和put(key,value)的时间复杂度都是O(1).
- 但是只使用哈希表,就无法记录最长时间没有被使用过的元素,所以我们再加入链表来记录元素,把存入的元素按照访问的先后顺序存入链表中,每次访问一个元素时,将该元素移到链表尾部。此时链表的头部的元素就是缓存中最长时间没有被使用过的元素。
源代码:
class LRUCache {
//创建链表
class ListNode{
ListNode front;
ListNode next;
int key;
int value;
public ListNode(int key,int value){
this.key = key;
this.value = value;
}
}
//创建两个哨兵节点
private ListNode head;
private ListNode tail;
//键为key,值为key所对应的节点
private Map<Integer,ListNode> map;
//记录缓存容量
int capacity;
public LRUCache(int capacity) {
map = new HashMap<>();
head = new ListNode(-1,-1);
tail = new ListNode(-1,-1);
head.next = tail;
tail.front = head;
this.capacity = capacity;
}
public int get(int key) {
ListNode node = map.get(key);
if(node == null){
return -1;
}
moveToTail(node,node.value);
return node.value;
}
public void put(int key, int value) {
if(map.containsKey(key)){
moveToTail(map.get(key),value);
}else{
if(map.size() == capacity){
ListNode node = head.next;
deleteNode(node);
map.remove(node.key);
}
ListNode newNode = new ListNode(key,value);
insertNode(newNode);
map.put(key,newNode);
}
}
//移动节点
private void moveToTail(ListNode node,int newValue){
deleteNode(node);
node.value = newValue;
insertNode(node);
}
//删除节点
private void deleteNode(ListNode node){
node.front.next = node.next;
node.next.front = node.front;
}
//添加节点
private void insertNode(ListNode node){
tail.front.next = node;
node.front = tail.front;
node.next = tail;
tail.front = node;
}
}