iT邦幫忙

2025 iThome 鐵人賽

DAY 14
0
自我挑戰組

leetcode解題學習java系列 第 14

30天LeetCode挑戰紀錄-DAY14. LRU Cache

  • 分享至 

  • xImage
  •  

題目

https://ithelp.ithome.com.tw/upload/images/20250928/20178158kwctXFeXHP.png
他說我們要設計一個LRU Cache (Least Recently Used Cache),時間複雜度為O(1),而且需要支援兩個動作。

  1. get(key):如果 key 存在於快取中,回傳對應的 value,否則回傳 -1。
  2. put(key,value):把 (key,value)放進快取。如果key已存在,就更新它的value;如果key不存在,就要檢查快取容量是不是滿了,如果快取滿了,就要刪除最久沒用的那個key,然後把新的值插入快取放到最新的位置。

Example 1:
Input
["LRUCache", "put", "put", "get", "put", "get", "put", "get", "get", "get"]
[[2], [1, 1], [2, 2], [1], [3, 3], [2], [4, 4], [1], [3], [4]]
Output
[null, null, null, 1, null, -1, null, -1, 3, 4]
LRUCache lru = new LRUCache(2); // 容量 = 2
lru.put(1, 1); // cache = {1=1}
lru.put(2, 2); // cache = {2=2, 1=1} (2最近被用)
lru.get(1); // return 1 → cache = {1=1, 2=2} (1最近被用)
lru.put(3, 3); // 容量滿了刪掉最舊的 key=2 → cache = {3=3, 1=1}
lru.get(2); // 因為2被淘汰了所以return -1
lru.put(4, 4); // 容量滿了刪掉最舊的 key=1 → cache = {4=4, 3=3}
lru.get(1); // 因為1被淘汰了所以return -1
lru.get(3); // return 3 → cache = {3=3, 4=4}
lru.get(4); // return 4 → cache = {4=4, 3=3}

想法

這題我想到的是HashMap+雙向鏈表,HashMap來存key對應的Node,然後雙向鏈表來管存取他們的順序,讓我們可以插入新的頭刪掉舊的尾。

程式碼

class LRUCache {
    class Node {
        int key, val;
        Node prev, next;
        Node(int key, int val) {
            this.key = key;
            this.val = val;
        }
    }

    private int cap;
    private HashMap<Integer, Node> map;
    private Node head, tail;

    public LRUCache(int capacity) {
        this.cap = capacity;
        this.map = new HashMap<>();
        //初始化head和tail
        head = new Node(-1, -1);
        tail = new Node(-1, -1);
        head.next = tail;
        tail.prev = head;
    }

    // 把節點移到頭部,變成最新的頭
    private void moveToHead(Node node) {
        remove(node);
        insertToHead(node);
    }

    // 插入到 head 後面
    private void insertToHead(Node node) {
        Node nextNode = head.next;
        head.next = node;
        node.prev = head;
        node.next = nextNode;
        nextNode.prev = node;
    }

    // 從鏈表中刪除節點
    private void remove(Node node) {
        Node p = node.prev;
        Node n = node.next;
        p.next = n;
        n.prev = p;
    }
    
    //查HashMap 找不到回傳-1;找到就取出來一道最新的位置,回傳他的值
    public int get(int key) {  
        if (!map.containsKey(key)) return -1;
        Node node = map.get(key);
        moveToHead(node); // 更新最近使用
        return node.val;
    }
    
   //key 已存在:更新值,移到最近使用。
   //key 不存在:容量滿了就刪掉最尾,然後從map刪掉。不然就建立一個節點放到最前,加入map
    public void put(int key, int value) {
        if (map.containsKey(key)) {
            // 已存在 → 更新值 + 移到頭
            Node node = map.get(key);
            node.val = value;
            moveToHead(node);
        } else {
            if (map.size() == cap) {
                // 滿了,移除尾巴前一個 (最久未使用的那一個)
                Node lru = tail.prev;
                remove(lru);
                map.remove(lru.key);
            }
            // 插入新節點
            Node newNode = new Node(key, value);
            insertToHead(newNode);
            map.put(key, newNode);
        }
    }
}

/**
 * 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);
 */

執行成功

https://ithelp.ithome.com.tw/upload/images/20250928/20178158qzUm1aJ7dO.png


上一篇
30天LeetCode挑戰紀錄-DAY13. Longest Consecutive Sequence
系列文
leetcode解題學習java14
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言