剑指Offer题目笔记9(哈希表的设计)

面试题30:

面试题30

问题:

​ 设计一个数据结构,使插入、删除和随机访问的时间复杂度是O(1)。

解决方案:
  1. 使用哈希表,可以让插入和删除的时间复杂度是O(1)。但是只使用哈希表,则不能等概率地返回其中的每个数值。
  2. 使用数组,可以等概率的返回每一个数值。将数值保存在数组中,然后用哈希表来存储数值在数组中所处的位置,哈希表的键为数值,值为数值在数组中所处的位置。
源代码:
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:

面试题31

问题:
  1. 设计实现缓存,使缓存的两个操作get(key)和put(key,value)的时间复杂度都是O(1)。
  2. 当进行put(key,value)操作时,缓存的容量满了,需要先缓存中最长时间没有被使用过的元素。
解决方案:
  1. 使用哈希表,哈希表的的两个操作get(key)和put(key,value)的时间复杂度都是O(1).
  2. 但是只使用哈希表,就无法记录最长时间没有被使用过的元素,所以我们再加入链表来记录元素,把存入的元素按照访问的先后顺序存入链表中,每次访问一个元素时,将该元素移到链表尾部。此时链表的头部的元素就是缓存中最长时间没有被使用过的元素。
源代码:
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;
    }
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值