LeetCode Summary
  • Introduction
  • DP, 动态规划类
    • Best Time to Buy and Sell Stock III 题解
    • Best Time to Buy and Sell Stock 题解
    • Climbing Stairs 题解
    • Decode Ways 题解
    • Distinct Subsequences 题解
    • Edit Distance 题解
    • Interleaving String 题解
    • Longest Palindromic Substring 题解
    • Maximum Product Subarray 题解
    • Maximum Subarray 题解
    • Minimum Path Sum 题解
    • Palindrome Partitioning 题解
    • Palindrome Partitioning II 题解
    • Scramble String 题解
    • Triangle 题解
    • Unique Binary Search Trees 题解
    • Unique Paths II 题解
    • Word Break 题解
    • Word Break II 题解
  • list, 链表相关
    • Add Two Numbers 题解
    • Convert Sorted List to Binary Search Tree 题解
    • Copy List with Random Pointer 题解
    • Insertion Sort List 题解
    • LRU Cache 题解
    • Linked List Cycle 题解
    • Linked List Cycle II 题解
    • Merge Two Sorted Lists 题解
    • Merge k Sorted Lists 题解
    • Partition List 题解
    • Remove Duplicates from Sorted List 题解
    • Remove Duplicates from Sorted List II 题解
    • Remove Nth Node From End of List 题解
    • Reorder List 题解
    • Reverse Linked List II 题解
    • Reverse Nodes in k-Group 题解
    • Rotate List 题解
    • Sort List 题解
    • Swap Nodes in Pairs 题解
  • binary tree, 二叉树相关
    • Balanced Binary Tree 题解
    • Binary Tree Inorder Traversal 题解
    • Binary Tree Level Order Traversal 题解
    • Binary Tree Level Order Traversal II 题解
    • Binary Tree Maximum Path Sum 题解
    • Binary Tree Postorder Traversal 题解
    • Binary Tree Preorder Traversal 题解
    • Binary Tree Zigzag Level Order Traversal 题解
    • Construct Binary Tree from Inorder and Postorder Traversal 题解
    • Construct Binary Tree from Preorder and Inorder Traversal 题解
    • Convert Sorted List to Binary Search Tree 题解
    • Flatten Binary Tree to Linked List 题解
    • Maximum Depth of Binary Tree 题解
    • Minimum Depth of Binary Tree 题解
    • Path Sum 题解
    • Path Sum II 题解
    • Populating Next Right Pointers in Each Node 题解
    • Populating Next Right Pointers in Each Node II 题解
    • Recover Binary Search Tree 题解
    • Same Tree 题解
    • Sum Root to Leaf Numbers 题解
    • Symmetric Tree 题解
    • Unique Binary Search Trees 题解
    • Unique Binary Search Trees II 题解
    • Validate Binary Search Tree 题解
  • sort, 排序相关
    • 3Sum Closest 题解
    • 3Sum 题解
    • 4Sum 题解
    • Insert Interval 题解
    • Longest Consecutive Sequence 题解
    • Merge Intervals 题解
    • Merge Sorted Array 题解
    • Remove Duplicates from Sorted Array 题解
    • Remove Duplicates from Sorted Array II 题解
    • Sort Colors 题解
    • Two Sum 题解
  • search, 搜索相关
    • First Missing Positive 题解
    • Find Minimum in Rotated Sorted Array 题解
    • Find Minimum in Rotated Sorted Array II 题解
    • Median of Two Sorted Arrays 题解
    • Search Insert Position 题解
    • Search a 2D Matrix 题解
    • Search for a Range 题解
    • Search in Rotated Sorted Array 题解
    • Search in Rotated Sorted Array II 题解
    • Single Number 题解
    • Single Number II 题解
  • math, 数学类相关
    • Add Binary 题解
    • Add Two Numbers 题解
    • Divide Two Integers 题解
    • Gray Code 题解
    • Integer to Roman 题解
    • Multiply Strings 题解
    • Palindrome Number 题解
    • Plus One 题解
    • [Pow(x, n) 题解](math/Pow(x,-n).md)
    • Reverse Integer 题解
    • Roman to Integer 题解
    • [Sqrt(x) 题解](math/Sqrt(x).md)
    • [String to Integer (atoi) 题解](math/String-to-Integer-(atoi).md)
    • Valid Number 题解
  • string, 字符串处理相关
    • Anagrams 题解
    • Count and Say 题解
    • Evaluate Reverse Polish Notation 题解
    • [Implement strStr() 题解](string/Implement-strStr().md)
    • Length of Last Word 题解
    • Longest Common Prefix 题解
    • Longest Palindromic Substring 题解
    • Longest Substring Without Repeating Characters 题解
    • Longest Valid Parentheses 题解
    • Minimum Window Substring 题解
    • Regular Expression Matching 题解
    • Reverse Words in a String 题解
    • Simplify Path 题解
    • Text Justification 题解
    • Valid Parentheses 题解
    • Wildcard Matching 题解
    • ZigZag Conversion 题解
  • combination and permutation, 排列组合相关
    • Combinations 题解
    • Combination Sum 题解
    • Combination Sum II 题解
    • Letter Combinations of a Phone Number 题解
    • Next Permutation 题解
    • Palindrome Partitioning 题解
    • Permutation Sequence 题解
    • Permutations 题解
    • Permutations II 题解
    • Subsets 题解
    • Subsets II 题解
    • Unique Paths 题解
  • matrix, 二维数组, 矩阵相关
    • Rotate Image 题解
    • Set Matrix Zeroes 题解
    • Spiral Matrix 题解
    • Spiral Matrix II 题解
    • Maximal Rectangle 题解
  • 回溯, BFS/DFS
    • Clone Graph 题解
    • Generate Parentheses 题解
    • N-Queens 题解
    • N-Queens II 题解
    • Restore IP Addresses 题解
    • Sudoku Solver 题解
    • Surrounded Regions 题解
    • Word Ladder 题解
    • Word Ladder II 题解
    • Word Search 题解
  • greedy, 贪心
    • Best Time to Buy and Sell Stock II 题解
    • Jump Game 题解
    • Jump Game II 题解
  • 其他
    • Candy 题解
    • Container With Most Water 题解
    • Gas Station 题解
    • Gray Code 题解
    • Max Points on a Line 题解
    • [Pascal's Triangle 题解](others/Pascal's-Triangle.md)
    • [Pascal's Triangle II 题解](others/Pascal's-Triangle-II.md)
    • Remove Element 题解
    • Trapping Rain Water 题解
Powered by GitBook
On this page

Was this helpful?

  1. list, 链表相关

LRU Cache 题解

PreviousInsertion Sort List 题解NextLinked List Cycle 题解

Last updated 5 years ago

Was this helpful?

题目来源:

> Design and implement a data structure for Least Recently Used (LRU) cache. It should support the following operations: get and set. > get(key) - Get the value (will always be positive) of the key if the key exists in the cache, otherwise return -1. set(key, value) - Set or insert the value if the key is not already present. When the cache reached its capacity, it should invalidate the least recently used item before inserting a new item.

解题思路:双向链表 + hashmap

Once the data with key K is queried, the function get(K) is first called. 
If the data of key K is in the cache, the cache just returns the data and refresh the data in the linked list. 
To refresh data T in the list, we move the item of data T to the head of the list. Otherwise, 
if the data T of key K is not in the cache, we need to insert the pair into the list. 
If the cache is not full, we insert into the hash map, and add the item at the head of the list. 
If the cache is already full, we get the tail of the list and update it with , then move this item to the head of the list.

LRU的典型实现是hash map + doubly linked list, 双向链表用于存储数据结点,并且它是按照结点最近被使用的时间来存储的。 如果一个结点被访问了,
我们有理由相信它在接下来的一段时间被访问的概率要大于其它结点。于是, 我们把它放到双向链表的头部。当我们往双向链表里插入一个结点, 我们也有可能很快就会使用到它,
同样把它插入到头部。 我们使用这种方式不断地调整着双向链表,链表尾部的结点自然也就是最近一段时间, 最久没有使用到的结点。那么,当我们的Cache满了, 
需要替换掉的就是双向链表中最后的那个结点(不是尾结点,头尾结点不存储实际内容)。

如下是双向链表示意图,注意头尾结点不存储实际内容:

头 --> 结 --> 结 --> 结 --> 尾
结     点     点     点     结
点 <-- 1  <-- 2 <-- 3  <-- 点
假如上图Cache已满了,我们要替换的就是结点3。

哈希表的作用是什么呢?如果没有哈希表,我们要访问某个结点,就需要顺序地一个个找, 时间复杂度是O(n)。使用哈希表可以让我们在O(1)的时间找到想要访问的结点, 
或者返回未找到。
    class LRUCache
    {
    public:
        struct Node
        {
            int value;
            int key;
            Node * prev;
            Node * next;
            Node(int k, int v): key(k),value(v),prev(NULL), next(NULL)
            {}
        };

        LRUCache(int capacity):capacity_(capacity) 
        {
            head = new Node(-1,-1);
            tail = new Node(-1,-1);
            head->next = tail;
            tail->prev = head;
        }

        ~LRUCache()
        {
            delete head;
            delete tail;
            for(auto it = kv_.begin(); it!=kv_.end(); it++)
                delete it->second;
        }

        int get(int key) 
        {
            auto it = kv_.find(key);
            if(it != kv_.end())
            {
                removeFromList(it->second);
                move2Head(it->second);
                return it->second->value;
            }
            return -1;
        }

        void set(int key, int value) 
        {
            auto it = kv_.find(key);
            if(it != kv_.end())//replace
            {
                removeFromList(it->second);
                it->second->value = value;
                move2Head(it->second);
            }else//insert new
            {
                if(kv_.size() >= capacity_)//remove tail
                {
                    auto node = tail->prev;
                    removeFromList(node);//!!Do not forget
                    kv_.erase(node->key);
                    node->key = key;
                    node->value = value;
                    kv_[key] = node;
                    move2Head(node);
                }else //add
                {
                    auto node = new Node(key, value);
                    kv_[key] = node;
                    move2Head(node);
                }
            }
        }
    private:
        Node * head; //head and tail do NOT store data
        Node * tail;
        unordered_map<int, Node*> kv_;
        int capacity_;
        void removeFromList(Node* node)
        {
            node->prev->next = node->next;
            node->next->prev = node->prev;
        }
        void move2Head(Node* node)
        {
            Node* old = head->next;
            old->prev = node;
            node->next = old;
            head->next = node;
            node->prev = head;
        }
    };
    class LRUCache
    {
    public:
        struct Node
        {
            int value;
            int key;
            Node(int k, int v): key(k),value(v)
            {}
        };

        LRUCache(int capacity):capacity_(capacity)
        {
        }

        int get(int key)
        {
            auto it = kv_.find(key);
            if(it != kv_.end())
            {
                //transfer: remove it from dataList, add to dataList.begin()
                //std::list::splice http://www.cplusplus.com/reference/list/list/splice/
                dataList.splice(dataList.begin(), dataList, it->second);
                it->second = dataList.begin();
                return it->second->value;
            }
            return -1;
        }

        void set(int key, int value)
        {
            auto it = kv_.find(key);
            if(it != kv_.end())//replace
            {
                dataList.splice(dataList.begin(), dataList, it->second);
                it->second = dataList.begin();
                it->second->value = value;
            }else//insert new
            {
                if(kv_.size() >= capacity_)//remove tail
                {
                    kv_.erase(dataList.back().key);
                    auto tail = dataList.back();
                    dataList.pop_back();
                    tail.key = key; tail.value = value;
                    dataList.push_front(tail);
                    kv_[key] = dataList.begin(); //insert
                }else
                {
                    dataList.push_front(Node(key, value));
                    kv_[key] = dataList.begin(); //insert
                }
            }
        }
    private:
        unordered_map<int, list<Node>::iterator> kv_;
        int capacity_;
        list<Node> dataList;
    };

看看人家用stl中的list写的,代码多短啊。 ref list中的方法

splice (iterator position, list& x, iterator i); Transfers elements from x into the container, inserting them at position.

LRU Cache
ref
ref1
leetcode-cpp
list api