LeetCode146. LRU ็ผ“ๅญ˜๐ŸŒŸ๐ŸŒŸ๐ŸŒŸ๐ŸŒŸไธญ็ญ‰

่ฏพๅŽไฝœไธš

้—ฎ้ข˜ๆ่ฟฐ

ๅŽŸๆ–‡้“พๆŽฅ๏ผš146. LRU ็ผ“ๅญ˜

่ฏทไฝ ่ฎพ่ฎกๅนถๅฎž็Žฐไธ€ไธชๆปก่ถณ LRU (ๆœ€่ฟ‘ๆœ€ๅฐ‘ไฝฟ็”จ) ็ผ“ๅญ˜็บฆๆŸ็š„ๆ•ฐๆฎ็ป“ๆž„ใ€‚

ๅฎž็Žฐ LRUCache ็ฑป๏ผš

  • LRUCache(int capacity) ไปฅๆญฃๆ•ดๆ•ฐไฝœไธบๅฎน้‡ capacity ๅˆๅง‹ๅŒ– LRU ็ผ“ๅญ˜
  • int get(int key) ๅฆ‚ๆžœๅ…ณ้”ฎๅญ— key ๅญ˜ๅœจไบŽ็ผ“ๅญ˜ไธญ๏ผŒๅˆ™่ฟ”ๅ›žๅ…ณ้”ฎๅญ—็š„ๅ€ผ๏ผŒๅฆๅˆ™่ฟ”ๅ›ž -1 ใ€‚
  • void put(int key, int value) ๅฆ‚ๆžœๅ…ณ้”ฎๅญ— key ๅทฒ็ปๅญ˜ๅœจ๏ผŒๅˆ™ๅ˜ๆ›ดๅ…ถๆ•ฐๆฎๅ€ผ value ๏ผ›ๅฆ‚ๆžœไธๅญ˜ๅœจ๏ผŒๅˆ™ๅ‘็ผ“ๅญ˜ไธญๆ’ๅ…ฅ่ฏฅ็ป„ key-value ใ€‚ๅฆ‚ๆžœๆ’ๅ…ฅๆ“ไฝœๅฏผ่‡ดๅ…ณ้”ฎๅญ—ๆ•ฐ้‡่ถ…่ฟ‡ capacity ๏ผŒๅˆ™ๅบ”่ฏฅ้€ๅ‡บๆœ€ไน…ๆœชไฝฟ็”จ็š„ๅ…ณ้”ฎๅญ—ใ€‚

ๅ‡ฝๆ•ฐ get ๅ’Œ put ๅฟ…้กปไปฅ O(1) ็š„ๅนณๅ‡ๆ—ถ้—ดๅคๆ‚ๅบฆ่ฟ่กŒใ€‚

็คบไพ‹๏ผš

่พ“ๅ…ฅ
["LRUCache", "put", "put", "get", "put", "get", "put", "get", "get", "get"]
[[2], [1, 1], [2, 2], [1], [3, 3], [2], [4, 4], [1], [3], [4]]
่พ“ๅ‡บ
[null, null, null, 1, null, -1, null, -1, 3, 4]

่งฃ้‡Š
LRUCache lRUCache = new LRUCache(2);
lRUCache.put(1, 1); // ็ผ“ๅญ˜ๆ˜ฏ {1=1}
lRUCache.put(2, 2); // ็ผ“ๅญ˜ๆ˜ฏ {1=1, 2=2}
lRUCache.get(1);    // ่ฟ”ๅ›ž 1
lRUCache.put(3, 3); // ่ฏฅๆ“ไฝœไผšไฝฟๅพ—ๅ…ณ้”ฎๅญ— 2 ไฝœๅบŸ๏ผŒ็ผ“ๅญ˜ๆ˜ฏ {1=1, 3=3}
lRUCache.get(2);    // ่ฟ”ๅ›ž -1 (ๆœชๆ‰พๅˆฐ)
lRUCache.put(4, 4); // ่ฏฅๆ“ไฝœไผšไฝฟๅพ—ๅ…ณ้”ฎๅญ— 1 ไฝœๅบŸ๏ผŒ็ผ“ๅญ˜ๆ˜ฏ {4=4, 3=3}
lRUCache.get(1);    // ่ฟ”ๅ›ž -1 (ๆœชๆ‰พๅˆฐ)
lRUCache.get(3);    // ่ฟ”ๅ›ž 3
lRUCache.get(4);    // ่ฟ”ๅ›ž 4

ๆ็คบ๏ผš

  • 1 <= capacity <= 3000
  • 0 <= key <= 10000
  • 0 <= value <= 105
  • ๆœ€ๅคš่ฐƒ็”จ 2 * 105 ๆฌก get ๅ’Œ put

ไปฃ็ ๅฎž็Žฐ

Java

class LRUCache {
    Map<Integer, Node> map = new HashMap();
    int capacity;
    int size;
    Node head;
    Node tail;

    public LRUCache(int capacity) {
        this.capacity = capacity;
        this.size = 0;

        this.head = new Node(-1, -1);
        this.tail = new Node(-2, -2);
        head.next = tail;
        tail.pre = head;

    }

    public int get(int key) {
        // ๅˆคๆ–ญๆ˜ฏๅฆๅญ˜ๅœจ
        Node tmp = map.get(key);
        if(tmp != null){
            // ๅˆ ้™ค
            delete(tmp);
            insertTohead(tmp);
            return tmp.value;
        }

        return -1;
    }

    public void put(int key, int value) {
        // ๅˆคๆ–ญkeyๆ˜ฏๅฆๅญ˜ๅœจ
        Node tmp = map.get(key);
        if(tmp != null){
            // ๅˆ ้™ค
            delete(tmp);
            // ๆ’ๅ…ฅๅˆฐๅคด้ƒจ
            tmp.value = value;
            insertTohead(tmp);
            return;
        }
        // ไธๅญ˜ๅœจ
        Node newHead = new Node(key, value);
        // ๆ’ๅ…ฅๅˆฐๅคด้ƒจ
        insertTohead(newHead);
        size++;
        map.put(key, newHead);
        if(size > capacity){
            // ๅˆ ้™คๆœ€ๅŽไธ€ไธช่Š‚็‚น
            Node res = tail.pre;
            delete(res);
            map.remove(res.key);
            size--;
        }
    }

    // ๆ’ๅ…ฅๅˆฐๅคด้ƒจhead->tmp->....
    public void insertTohead(Node tmp){
        tmp.next = head.next;
        head.next.pre = tmp;
        head.next = tmp;
        tmp.pre = head;
    }

    // ๅˆ ้™คtmp่Š‚็‚น
    public void delete(Node tmp){
        tmp.pre.next = tmp.next;
        tmp.next.pre = tmp.pre;
    }



    // ๅฎšไน‰ๅŒๅ‘้“พ่กจ
    class Node{
        int value;
        int key;
        Node next;
        Node pre;

        public Node(int key, int value){
            this.key = key;
            this.value = value;
        }
    }




    // ้ข่ฏ•ไธญ่€ƒ็š„ๆŒบๅคš=ใ€‹้ขๅคงๅŽ‚=ใ€‰ๆŽŒๆก

    /*ๆ–นๆณ•1:ๅ•้“พ่กจ

    head->(4,4)->(3,3)->null

    put:
    1.ไธๅญ˜ๅœจ๏ผŒ็›ดๆŽฅๆŠŠ่Š‚็‚นๆ’ๅ…ฅๅˆฐๅคด้ƒจ
    2.ๅฆ‚ๆžœๅญ˜ๅœจ๏ผŒๆŠŠ่ฟ™ไธช่Š‚็‚นไปŽ้“พ่กจไธญๅˆ ้™ค๏ผŒๅนถไธ”ๆ’ๅ…ฅๅˆฐๅคด้ƒจ
    3.ๅฆ‚ๆžœๆ’ๅ…ฅๅผ๏ผŒ่ถ…่ฟ‡ๆœ€ๅคงๅฎน้‡๏ผŒๅˆ™้“พ่กจๆœ€ๅŽไธ€ไธช่Š‚็‚นๅˆ ้™ค

    get:ๅฆ‚ๆžœๅญ˜ๅœจ๏ผŒๅˆ™่ฟ”ๅ›ž๏ผŒๅนถไธ”ๆŠŠ่Š‚็‚นๅˆ ้™ค+ๆ’ๅ…ฅๅˆฐ้“พ่กจๅคด้ƒจ
        ๅฆ‚ๆžœไธๅญ˜ๅœจ๏ผŒๅˆ™็›ดๆŽฅ่ฟ”ๅ›ž-1๏ผŒๅ…ถไป–้ƒฝไธ็”จๆ“ไฝœ

    ๆ—ถ้—ดๅคๆ‚ๅบฆ๏ผšput:O(n). get:O(n)


    # ไผ˜ๅŒ–1๏ผšๅŠ ๅ“ˆๅธŒ่กจ <key,Node>
   ็œ‹ไผผO(1)๏ผŒไฝ†ๅ…ถๅฎžไธ่ƒฝO(1)๏ผŒๅ› ไธบ่ฟ˜้œ€่ฆๅˆ ้™ค่Š‚็‚น๏ผŒๅˆ ้™ค่Š‚็‚น้œ€่ฆ
   ๆ‰พๅˆฐๅ‰้ฉฑ่Š‚็‚น๏ผŒๆ‰พๅ‰้ฉฑ่Š‚็‚น็š„่ฟ‡็จ‹ไนŸ้œ€่ฆO๏ผˆn)

   # ็ปง็ปญไผ˜ๅŒ–๏ผšๅŒๅ‘้“พ่กจ + ๅ“ˆๅธŒ่กจ
   ๅฏไปฅO(1)
   ๆผ”็คบ๏ผš
   head<->(3,3)<->(4,4)<->tail
    */

}

/**
 * Your LRUCache object will be instantiated and called as such:
 * LRUCache obj = new LRUCache(capacity);
 * int param_1 = obj.get(key);
 * obj.put(key,value);
 */

Python

class LRUCache(object):
    def __init__(self, capacity):
        """
        :type capacity: int
        """
        self.map = {}
        self.capacity = capacity
        self.size = 0

        self.head = Node(-1, -1)
        self.tail = Node(-2, -2)
        self.head.next = self.tail
        self.tail.pre = self.head

    def get(self, key):
        """
        :type key: int
        :rtype: int
        """
        # ๅˆคๆ–ญๆ˜ฏๅฆๅญ˜ๅœจ
        tmp = self.map.get(key)
        if tmp:
            # ๅˆ ้™ค
            self.delete(tmp)
            self.insertTohead(tmp)
            return tmp.value
        return -1

    def put(self, key, value):
        """
        :type key: int
        :type value: int
        :rtype: None
        """
        # ๅˆคๆ–ญkeyๆ˜ฏๅฆๅญ˜ๅœจ
        tmp = self.map.get(key)
        if tmp:
            # ๅˆ ้™ค
            self.delete(tmp)
            # ๆ’ๅ…ฅๅˆฐๅคด้ƒจ
            tmp.value = value
            self.insertTohead(tmp)
            return
        # ไธๅญ˜ๅœจ
        newHead = Node(key, value)
        # ๆ’ๅ…ฅๅˆฐๅคด้ƒจ
        self.insertTohead(newHead)
        self.size += 1
        self.map[key] = newHead
        if self.size > self.capacity:
            # ๅˆ ้™คๆœ€ๅŽไธ€ไธช่Š‚็‚น
            res = self.tail.pre
            self.delete(res)
            self.map.pop(res.key)
            self.size -= 1

    # ๆ’ๅ…ฅๅˆฐๅคด้ƒจhead->tmp->....
    def insertTohead(self, tmp):
        tmp.next = self.head.next
        self.head.next.pre = tmp
        self.head.next = tmp
        tmp.pre = self.head

    # ๅˆ ้™คtmp่Š‚็‚น
    def delete(self, tmp):
        tmp.pre.next = tmp.next
        tmp.next.pre = tmp.pre

# ๅฎšไน‰ๅŒๅ‘้“พ่กจ
class Node:
    def __init__(self, key, value):
        self.key = key
        self.value = value
        self.next = None
        self.pre = None

C++

class LRUCache {
public:
    LRUCache(int capacity) {
        this->capacity = capacity;
        size = 0;

        // ๅˆๅง‹ๅŒ–ๅคดๅฐพ่Š‚็‚น
        this->head = new Node(-1, -1);
        this->tail = new Node(-2, -2);
        head->next = tail;
        tail->pre = head;

    }

    int get(int key) {
        // ๅˆคๆ–ญๆ˜ฏๅฆๅญ˜ๅœจ
        Node* tmp = map[key];
        if(tmp != nullptr){
            // ๅˆ ้™ค
            deleteNode(tmp);
            // ๆ’ๅ…ฅๅˆฐๅคด้ƒจ
            insertToHead(tmp);
            return tmp->value;
        }

        return -1;
    }

    void put(int key, int value) {
        // ๅˆคๆ–ญkeyๆ˜ฏๅฆๅญ˜ๅœจ
        Node* tmp = map[key];
        if(tmp != nullptr){
            // ๅˆ ้™ค
            deleteNode(tmp);
            // ๆ’ๅ…ฅๅˆฐๅคด้ƒจ
            tmp->value = value;
            insertToHead(tmp);
            return;
        }
        // ไธๅญ˜ๅœจ
        Node* newHead = new Node(key, value);
        // ๆ’ๅ…ฅๅˆฐๅคด้ƒจ
        insertToHead(newHead);
        size++;
        map[key] = newHead;
        if(size > capacity){
            // ๅˆ ้™คๆœ€ๅŽไธ€ไธช่Š‚็‚น
            Node* res = tail->pre;
            deleteNode(res);
            map.erase(res->key);
            size--;
        }
    }

private:
    // ๅฎšไน‰ๅŒๅ‘้“พ่กจ
    struct Node{
        int value;
        int key;
        Node* next;
        Node* pre;

        Node(int k, int v){
            this->key = k;
            this->value = v;
            next = nullptr;
            pre = nullptr;
        }
    };
    unordered_map<int, Node*> map; // key->NodeๆŒ‡้’ˆ
    int capacity; // ๆœ€ๅคงๅฎน้‡
    int size; // ๅฝ“ๅ‰ๅคงๅฐ
    Node* head; // ๅŒๅ‘้“พ่กจๅคด่Š‚็‚น
    Node* tail; // ๅŒๅ‘้“พ่กจๅฐพ่Š‚็‚น

    // ๆ’ๅ…ฅๅˆฐๅคด้ƒจhead->tmp->....
    void insertToHead(Node* tmp){
        tmp->next = head->next;
        head->next->pre = tmp;
        head->next = tmp;
        tmp->pre = head;
    }

    // ๅˆ ้™ค่Š‚็‚น
    void deleteNode(Node* tmp){
        tmp->pre->next = tmp->next;
        tmp->next->pre = tmp->pre;
    }
};

Go

type LRUCache struct {
    mapCache  map[int]*Node
    capacity  int
    size      int
    head, tail  *Node
}

type Node struct {
    key, value int
    prev, next *Node
}

// ๆž„้€ ๅ‡ฝๆ•ฐ
func Constructor(capacity int) LRUCache {
    lru := LRUCache{
        mapCache: make(map[int]*Node),
        capacity: capacity,
        size:     0,
        head:     &Node{key: -1, value: -1},
        tail:     &Node{key: -2, value: -2},
    }
    lru.head.next = lru.tail
    lru.tail.prev = lru.head
    return lru
}

// getๆ–นๆณ•
func (this *LRUCache) Get(key int) int {
    if node, ok := this.mapCache[key]; ok {
        // ๅฆ‚ๆžœๅญ˜ๅœจ๏ผŒๅˆ ้™ค่ฏฅ่Š‚็‚นๅนถๆ’ๅ…ฅๅˆฐๅคด้ƒจ
        this.deleteNode(node)
        this.insertToHead(node)
        return node.value
    }
    return -1
}

// putๆ–นๆณ•
func (this *LRUCache) Put(key int, value int) {
    if node, ok := this.mapCache[key]; ok {
        // ๅฆ‚ๆžœๅญ˜ๅœจ๏ผŒๅˆ ้™ค่ฏฅ่Š‚็‚นๅนถๆ’ๅ…ฅๅˆฐๅคด้ƒจ
        this.deleteNode(node)
        node.value = value
        this.insertToHead(node)
    } else {
        // ๅฆ‚ๆžœไธๅญ˜ๅœจ๏ผŒๅˆ›ๅปบๆ–ฐ่Š‚็‚นๅนถๆ’ๅ…ฅๅˆฐๅคด้ƒจ
        newNode := &Node{key: key, value: value}
        this.insertToHead(newNode)
        this.mapCache[key] = newNode
        this.size++
        if this.size > this.capacity {
            // ๅฆ‚ๆžœ่ถ…่ฟ‡ๆœ€ๅคงๅฎน้‡๏ผŒๅˆ ้™คๅฐพ้ƒจ่Š‚็‚น
            tailNode := this.tail.prev
            this.deleteNode(tailNode)
            delete(this.mapCache, tailNode.key)
            this.size--
        }
    }
}

// ๅœจๅคด้ƒจๆ’ๅ…ฅไธ€ไธช่Š‚็‚น
func (this *LRUCache) insertToHead(node *Node) {
    node.next = this.head.next
    this.head.next.prev = node
    this.head.next = node
    node.prev = this.head
}

// ๅˆ ้™คไธ€ไธช่Š‚็‚น
func (this *LRUCache) deleteNode(node *Node) {
    node.prev.next = node.next
    node.next.prev = node.prev
}

ๅ‘่กจ่ฏ„่ฎบ

ๅŽๆ‰่ƒฝ่ฏ„่ฎบ