1. 程式人生 > >[LeetCode]146.LRU緩存機制

[LeetCode]146.LRU緩存機制

problem span 密鑰 單向 arraylist per pri integer .com

設計和實現一個 LRU(最近最少使用)緩存 數據結構,使它應該支持以下操作: getput

get(key) - 如果密鑰存在於緩存中,則獲取密鑰的值(總是正數),否則返回 -1。
put(key, value) - 如果密鑰不存在,請設置或插入值。當緩存達到其容量時,它應該在插入新項目之前使最近最少使用的項目作廢。

後續:

你是否可以在 O(1) 時間復雜度中進行兩種操作?註:這道題也是2018今日頭條春招面試題。

案例:

LRUCache cache = new LRUCache( 2 /* 容量 */ );

cache.put(1, 1);
cache.put(2, 2);
cache.get(1);       // 返回  1
cache.put(3, 3);    // 該操作,會將 key 2 作廢
cache.get(2);       // 返回 -1 (結果不存在)
cache.put(4, 4);    // 該操作,會將 key 1 作廢
cache.get(1);       // 返回 -1 (結果不存在)
cache.get(3);       // 返回  3
cache.get(4);       // 返回  4

求解思路:其實這道題並不難,就是找一個合適的數據結構去存儲,每次get之後,要把get到的數提前到最前面,如果沒有get到,則返回-1。put的時候,先查看有沒有相同的key元素,有的話,直接把那個刪掉,否則不做處理。然後判斷當前的元素個數是否小於capacity,小於的話就在最前面添加新元素即可,否則在最前面添加新元素之後,還要把最後面的元素刪掉。

思路簡單,難的是時間復雜度,我最開始直接想的是利用現成的數據結構,就用的是Java中的LinkedList和HashMap,HashMap中存儲的是key和value,LinkedList中存儲的是若幹個map。代碼如下:

package
com.darrenchan.dp; import java.util.HashMap; import java.util.LinkedList; import java.util.List; import java.util.Map; class LRUCache2 { public int capacity; public List<Map<Integer, Integer>> list = new LinkedList<>(); public LRUCache2(int capacity) {
this.capacity = capacity; } public int get(int key) { int value = -1; for (Map<Integer, Integer> map : list) { if(map.get(key) != null){ value = map.get(key); list.remove(map); list.add(0, map); break; } } return value; } public void put(int key, int value) { int index = -1; for (Map<Integer, Integer> map : list) { if(map.get(key) != null){ list.remove(map); break; } } int size = list.size(); Map<Integer, Integer> map = new HashMap<>(); map.put(key, value); if(size < capacity){ list.add(0, map); }else{ list.add(0, map); list.remove(capacity); } } public static void main(String[] args) { LRUCache2 lruCache = new LRUCache2(2); System.out.println(lruCache.get(2)); lruCache.put(2, 6); System.out.println(lruCache.get(1)); lruCache.put(1, 5); lruCache.put(1, 2); System.out.println(lruCache.get(1)); System.out.println(lruCache.get(2)); } }

這樣時間復雜度是O(N),因為每次需要for循環,時間超時。看來不能用現成的了,需要自己構造一個數據結構,這裏采用雙向鏈表和HashMap的結構,HashMap中存儲的是key和Node,Node中存儲的是key和value。HashMap能保證查找的時間復雜度是O(1),雙向鏈表保證的是增刪的時間復雜度是O(1),當然用單向鏈表也可以,就是不太方便。代碼如下:

package com.darrenchan.dp;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

class LRUCache3 {
    
    public int capacity;
    public Map<Integer, Node> map;
    public Node head;//設一個虛擬的頭結點
    public Node tail;//設一個虛擬的尾結點
    public int size;//鏈表長度
    
    public LRUCache3(int capacity) {
        this.capacity = capacity;
        this.map = new HashMap<>();
        head = new Node(0, 0);
        tail = new Node(0, 0);
        
        head.pre = null;
        head.next = tail;
        tail.pre = head;
        tail.next = null;
    }
    
    public void removeNode(Node node){
        node.pre.next = node.next;
        node.next.pre = node.pre;
    }
    
    public void addToHead(Node node){
        node.next = head.next;
        node.next.pre = node;
        node.pre = head;
        head.next = node;
    }
    
    public int get(int key) {
        int value = -1;
        if(map.get(key) != null){
            value = map.get(key).value;
            removeNode(map.get(key));
            addToHead(map.get(key));
        }
        return value;
    }
    
    public void put(int key, int value) {
        if(map.get(key) != null){
            removeNode(map.get(key));
            map.remove(key);
            size--;
        }
        Node node = new Node(key, value);
        map.put(key, node);
        if(size < capacity){
            addToHead(node);
            size++;
        }else{
            Node remove = tail.pre;
            removeNode(remove);
            map.remove(remove.key);
            addToHead(node);
        }
    }
    
    public static void main(String[] args) {
        LRUCache3 lruCache = new LRUCache3(2);
        System.out.println(lruCache.get(2));
        lruCache.put(2, 6);
        System.out.println(lruCache.get(1));
        lruCache.put(1, 5);
        lruCache.put(1, 2);
        System.out.println(lruCache.get(1));
        System.out.println(lruCache.get(2));
    }
}

class Node{
    int key;
    int value;
    public Node(int key, int value) {
        super();
        this.key = key;
        this.value = value;
    }
    Node pre;
    Node next;
}

原題鏈接:https://leetcode-cn.com/problems/lru-cache/description/

[LeetCode]146.LRU緩存機制