<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>LRU &#8211; Huahua&#8217;s Tech Road</title>
	<atom:link href="https://zxi.mytechroad.com/blog/tag/lru/feed/" rel="self" type="application/rss+xml" />
	<link>https://zxi.mytechroad.com/blog</link>
	<description></description>
	<lastBuildDate>Wed, 11 Jul 2018 01:30:08 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=6.7.5</generator>

<image>
	<url>https://zxi.mytechroad.com/blog/wp-content/uploads/2017/09/cropped-photo-32x32.jpg</url>
	<title>LRU &#8211; Huahua&#8217;s Tech Road</title>
	<link>https://zxi.mytechroad.com/blog</link>
	<width>32</width>
	<height>32</height>
</image> 
	<item>
		<title>花花酱 LeetCode 460. LFU Cache</title>
		<link>https://zxi.mytechroad.com/blog/hashtable/leetcode-460-lfu-cache/</link>
					<comments>https://zxi.mytechroad.com/blog/hashtable/leetcode-460-lfu-cache/#respond</comments>
		
		<dc:creator><![CDATA[zxi]]></dc:creator>
		<pubDate>Thu, 14 Sep 2017 07:36:55 +0000</pubDate>
				<category><![CDATA[Data Structure]]></category>
		<category><![CDATA[Hashtable]]></category>
		<category><![CDATA[cache]]></category>
		<category><![CDATA[hashtable]]></category>
		<category><![CDATA[LFU]]></category>
		<category><![CDATA[list]]></category>
		<category><![CDATA[LRU]]></category>
		<category><![CDATA[tree]]></category>
		<guid isPermaLink="false">http://zxi.mytechroad.com/blog/?p=264</guid>

					<description><![CDATA[Problem: Design and implement a data structure for Least Frequently Used (LFU) cache. It should support the following operations: get and put. get(key) &#8211; Get the value (will always be positive)&#8230;]]></description>
										<content:encoded><![CDATA[<p><iframe title="LeetCode 460. LFU Cache / O(1)  - 花花酱 刷题找工作 EP54" width="500" height="375" src="https://www.youtube.com/embed/MCTN3MM8vHA?feature=oembed" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen></iframe></p>
<p><strong>Problem:</strong></p>
<div class="question-description">
<p>Design and implement a data structure for <a href="https://en.wikipedia.org/wiki/Least_frequently_used" target="_blank" rel="noopener">Least Frequently Used (LFU)</a> cache. It should support the following operations: <code>get</code> and <code>put</code>.</p>
<p><code>get(key)</code> &#8211; Get the value (will always be positive) of the key if the key exists in the cache, otherwise return -1.<br />
<code>put(key, value)</code> &#8211; Set or insert the value if the key is not already present. When the cache reaches its capacity, it should invalidate the least frequently used item before inserting a new item. For the purpose of this problem, when there is a tie (i.e., two or more keys that have the same frequency), the least <b>recently</b> used key would be evicted.</p>
<p><b>Follow up:</b><br />
Could you do both operations in <b>O(1)</b> time complexity?</p>
<p><b>Example:</b></p><pre class="urvanov-syntax-highlighter-plain-tag">LFUCache cache = new LFUCache( 2 /* capacity */ );

cache.put(1, 1);
cache.put(2, 2);
cache.get(1);       // returns 1
cache.put(3, 3);    // evicts key 2
cache.get(2);       // returns -1 (not found)
cache.get(3);       // returns 3.
cache.put(4, 4);    // evicts key 1.
cache.get(1);       // returns -1 (not found)
cache.get(3);       // returns 3
cache.get(4);       // returns 4</pre><p>
</div>
<div id="interviewed-div"><strong>Idea:</strong></div>
<div></div>
<div>Hashtable + balanced search tree</div>
<div></div>
<div>Hashtable + double linked list</div>
<div></div>
<div><a href="http://zxi.mytechroad.com/blog/wp-content/uploads/2017/09/460-ep54-1.png"><img fetchpriority="high" decoding="async" class="alignnone size-full wp-image-271" src="http://zxi.mytechroad.com/blog/wp-content/uploads/2017/09/460-ep54-1.png" alt="" width="960" height="540" srcset="https://zxi.mytechroad.com/blog/wp-content/uploads/2017/09/460-ep54-1.png 960w, https://zxi.mytechroad.com/blog/wp-content/uploads/2017/09/460-ep54-1-300x169.png 300w, https://zxi.mytechroad.com/blog/wp-content/uploads/2017/09/460-ep54-1-768x432.png 768w, https://zxi.mytechroad.com/blog/wp-content/uploads/2017/09/460-ep54-1-624x351.png 624w" sizes="(max-width: 960px) 100vw, 960px" /></a><img decoding="async" class="alignnone size-full wp-image-270" style="font-size: 1rem;" src="http://zxi.mytechroad.com/blog/wp-content/uploads/2017/09/460-ep54-2.png" alt="" width="960" height="540" srcset="https://zxi.mytechroad.com/blog/wp-content/uploads/2017/09/460-ep54-2.png 960w, https://zxi.mytechroad.com/blog/wp-content/uploads/2017/09/460-ep54-2-300x169.png 300w, https://zxi.mytechroad.com/blog/wp-content/uploads/2017/09/460-ep54-2-768x432.png 768w, https://zxi.mytechroad.com/blog/wp-content/uploads/2017/09/460-ep54-2-624x351.png 624w" sizes="(max-width: 960px) 100vw, 960px" /><a href="http://zxi.mytechroad.com/blog/wp-content/uploads/2017/09/460-ep54-3.png"><img loading="lazy" decoding="async" class="alignnone size-full wp-image-269" src="http://zxi.mytechroad.com/blog/wp-content/uploads/2017/09/460-ep54-3.png" alt="" width="960" height="540" srcset="https://zxi.mytechroad.com/blog/wp-content/uploads/2017/09/460-ep54-3.png 960w, https://zxi.mytechroad.com/blog/wp-content/uploads/2017/09/460-ep54-3-300x169.png 300w, https://zxi.mytechroad.com/blog/wp-content/uploads/2017/09/460-ep54-3-768x432.png 768w, https://zxi.mytechroad.com/blog/wp-content/uploads/2017/09/460-ep54-3-624x351.png 624w" sizes="auto, (max-width: 960px) 100vw, 960px" /></a></div>
<div></div>
<div><strong>Solution 1: </strong>O(logc) c is the capacity</div>
<div>
</p><pre class="urvanov-syntax-highlighter-plain-tag">// Author: Huahua
// Running time: 99 ms
struct CacheNode {
    int key;
    int value;
    int freq;
    long tick;
    
    // Defines the order, smaller one will be evicted first
    bool operator &lt;(const CacheNode&amp; rhs) const {
        if (freq &lt; rhs.freq) return true;
        if (freq == rhs.freq) return tick &lt; rhs.tick;
        return false;
    }
};
class LFUCache {
public:
    LFUCache(int capacity):capacity_(capacity), tick_(0) {}
    
    int get(int key) {
        auto it = m_.find(key);
        if (it == m_.cend()) return -1;
        int value = it-&gt;second.value;
        touch(it-&gt;second);
        return value;
    }
    
    void put(int key, int value) {
        if (capacity_ == 0) return;
        
        auto it = m_.find(key);
        
        if (it != m_.cend()) {
            // Key exists, update value and touch
            it-&gt;second.value = value;            
            touch(it-&gt;second);            
            return;
        }
        
        if (m_.size() == capacity_) {
            // Remove the first node in cache
            const CacheNode&amp; node = *cache_.cbegin();
            m_.erase(node.key);
            cache_.erase(node);
        }
        
        CacheNode node{key, value, 1, ++tick_};
        m_[node.key] = node;
        cache_.insert(node);
    }
private:
    void touch(CacheNode&amp; node) {
        cache_.erase(node);     // log(capacity)        
        ++node.freq;
        node.tick = ++tick_;
        cache_.insert(node);    // log(capacity)
    }
    
    long tick_;
    int capacity_;
    unordered_map&lt;int, CacheNode&gt; m_;
    set&lt;CacheNode&gt; cache_;
    
};</pre><p>
</div>
<p><strong>Solution 2: </strong>O(1)</p><pre class="urvanov-syntax-highlighter-plain-tag">// Author: Huahua
// Running time: 89 ms (beats 96.3%)

struct CacheNode {
    int key;
    int value;
    int freq;
    // pointer to the node in the list
    list&lt;int&gt;::const_iterator it;
};

class LFUCache {
public:
    LFUCache(int capacity): capacity_(capacity), min_freq_(0) {}
    
    int get(int key) {
        auto it = n_.find(key);
        if (it == n_.cend()) return -1;
        touch(it-&gt;second);
        return it-&gt;second.value;
    }
    
    void put(int key, int value) {
        if (capacity_ == 0) return;
        
        auto it = n_.find(key);
        if (it != n_.cend()) {
            // Key already exists, update the value and touch it
            it-&gt;second.value = value;
            touch(it-&gt;second);
            return;
        }
        
        if (n_.size() == capacity_) {
            // No capacity, need to remove one entry that
            // 1. has the lowest freq
            // 2. least recently used if there are multiple ones
            
            // Step 1: remove the element from min_freq_ list
            const int key_to_evict = l_[min_freq_].back();
            l_[min_freq_].pop_back();
            
            // Step 2: remove the key from cache
            n_.erase(key_to_evict);
        }
        
        // We know new item has freq of 1, thus set min_freq to 1
        const int freq = 1;
        min_freq_ = freq;
        
        // Add the key to the freq list
        l_[freq].push_front(key);
        
        // Create a new node
        n_[key] = {key, value, freq, l_[freq].cbegin()};
    }
private:
    void touch(CacheNode&amp; node) {
        // Step 1: update the frequency
        const int prev_freq = node.freq;
        const int freq = ++(node.freq);
        
        // Step 2: remove the entry from old freq list
        l_[prev_freq].erase(node.it);
        
        if (l_[prev_freq].empty() &amp;&amp; prev_freq == min_freq_) {
            // Delete the list
            l_.erase(prev_freq);
            
            // Increase the min freq
            ++min_freq_;
        }
        
        // Step 4: insert the key into the front of the new freq list
        l_[freq].push_front(node.key);
        
        // Step 5: update the pointer
        node.it = l_[freq].cbegin();
    }
    
    int capacity_;
    int min_freq_;
    
    // key -&gt; CacheNode
    unordered_map&lt;int, CacheNode&gt; n_;
    
    // freq -&gt; keys with freq
    unordered_map&lt;int, list&lt;int&gt;&gt; l_;
};</pre><p>&nbsp;</p>
]]></content:encoded>
					
					<wfw:commentRss>https://zxi.mytechroad.com/blog/hashtable/leetcode-460-lfu-cache/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
	</channel>
</rss>
