solution.md 10.2 KB
Newer Older
每日一练社区's avatar
每日一练社区 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392
# LFU 缓存
<p>请你为 <a href="https://baike.baidu.com/item/%E7%BC%93%E5%AD%98%E7%AE%97%E6%B3%95">最不经常使用(LFU)</a>缓存算法设计并实现数据结构。</p>

<p>实现 <code>LFUCache</code> 类:</p>

<ul>
	<li><code>LFUCache(int capacity)</code> - 用数据结构的容量 <code>capacity</code> 初始化对象</li>
	<li><code>int get(int key)</code> - 如果键存在于缓存中,则获取键的值,否则返回 -1。</li>
	<li><code>void put(int key, int value)</code> - 如果键已存在,则变更其值;如果键不存在,请插入键值对。当缓存达到其容量时,则应该在插入新项之前,使最不经常使用的项无效。在此问题中,当存在平局(即两个或更多个键具有相同使用频率)时,应该去除 <strong>最近最久未使用</strong> 的键。</li>
</ul>

<p><strong>注意</strong>「项的使用次数」就是自插入该项以来对其调用 <code>get</code><code>put</code> 函数的次数之和。使用次数会在对应项被移除后置为 0 。</p>

<p>为了确定最不常使用的键,可以为缓存中的每个键维护一个 <strong>使用计数器</strong> 。使用计数最小的键是最久未使用的键。</p>

<p>当一个键首次插入到缓存中时,它的使用计数器被设置为 <code>1</code> (由于 put 操作)。对缓存中的键执行 <code>get</code><code>put</code> 操作,使用计数器的值将会递增。</p>

<p> </p>

<p><strong>示例:</strong></p>

<pre>
<strong>输入:</strong>
["LFUCache", "put", "put", "get", "put", "get", "get", "put", "get", "get", "get"]
[[2], [1, 1], [2, 2], [1], [3, 3], [2], [3], [4, 4], [1], [3], [4]]
<strong>输出:</strong>
[null, null, null, 1, null, -1, 3, null, -1, 3, 4]

<strong>解释:</strong>
// cnt(x) = 键 x 的使用计数
// cache=[] 将显示最后一次使用的顺序(最左边的元素是最近的)
LFUCache lFUCache = new LFUCache(2);
lFUCache.put(1, 1);   // cache=[1,_], cnt(1)=1
lFUCache.put(2, 2);   // cache=[2,1], cnt(2)=1, cnt(1)=1
lFUCache.get(1);      // 返回 1
                      // cache=[1,2], cnt(2)=1, cnt(1)=2
lFUCache.put(3, 3);   // 去除键 2 ,因为 cnt(2)=1 ,使用计数最小
                      // cache=[3,1], cnt(3)=1, cnt(1)=2
lFUCache.get(2);      // 返回 -1(未找到)
lFUCache.get(3);      // 返回 3
                      // cache=[3,1], cnt(3)=2, cnt(1)=2
lFUCache.put(4, 4);   // 去除键 1 ,1 和 3 的 cnt 相同,但 1 最久未使用
                      // cache=[4,3], cnt(4)=1, cnt(3)=2
lFUCache.get(1);      // 返回 -1(未找到)
lFUCache.get(3);      // 返回 3
                      // cache=[3,4], cnt(4)=1, cnt(3)=3
lFUCache.get(4);      // 返回 4
                      // cache=[3,4], cnt(4)=2, cnt(3)=3</pre>

<p> </p>

<p><strong>提示:</strong></p>

<ul>
	<li><code>0 <capacity, key, value <= 10<sup>4</sup></code></li>
	<li>最多调用 <code>10<sup>5</sup></code><code>get</code><code>put</code> 方法</li>
</ul>

<p> </p>

<p><strong>进阶:</strong>你可以为这两种操作设计时间复杂度为 <code>O(1)</code> 的实现吗?</p>

<p>以下错误的选项是?</p>
## aop
### before
```cpp
#include <bits/stdc++.h>
using namespace std;
```
### after
```cpp

```

## 答案
```cpp
class LFUCache
{
private:
    int cap;
    int size;
    int minfre;
    unordered_map<int, pair<int, int>> m;
    unordered_map<int, list<int>> hash_fre;
    unordered_map<int, list<int>::iterator> hash_node;

public:
    LFUCache(int capacity) : cap(capacity), size(0) {}

    int get(int key)
    {
        if (m.count(key) == 0)
            return -1;

        hash_fre[m[key].second].erase(hash_node[key]);
        m[key].second++;
        hash_fre[m[key].second].push_back(key);
        hash_node[key] = --hash_fre[m[key].second].end();
        if (hash_fre[minfre].size() == 0)
        {
            minfre++;
        }
        return m[key].first;
    }

    void put(int key, int value)
    {
        if (cap <= 0)
            return;
        if (get(key) != -1)
        {
            m[key].first = value;
            return;
        }

        if (size >= cap)
        {
            m.erase(hash_fre[minfre].front());
            hash_node.erase(hash_fre[minfre].front());
            hash_fre[minfre].pop_front();
        }

        m[key] = {value, 1};
        hash_fre[1].push_back(key);
        hash_node[key] = hash_fre[1].end();
        minfre = 1;
        if (size < cap)
            size++;
    }
};
```
## 选项

### A
```cpp
class Node
{
public:
    int cnt;
    int time;
    int key;
    int val;
    Node(int cnt, int time, int key, int val)
    {
        this->cnt = cnt;
        this->time = time;
        this->key = key;
        this->val = val;
    }
    bool operator<(const Node &n) const
    {
        if (n.cnt == cnt)
            return time < n.time;
        return cnt < n.cnt;
    }
};
class LFUCache
{
public:
    int size;
    int time;
    unordered_map<int, Node> LFU;
    set<Node> tree;
    LFUCache(int capacity)
    {
        time = 0;
        size = capacity;
    }

    int get(int key)
    {
        if (LFU.count(key) == 0)
            return -1;
        unordered_map<int, Node>::iterator iter = LFU.find(key);
        Node now = (*iter).second;
        tree.erase(now);
        now.cnt++;
        now.time = time++;
        tree.insert(now);
        (*iter).second = now;
        return now.val;
    }

    void put(int key, int value)
    {
        if (LFU.count(key) == 0)
        {
            Node newNode = Node(1, time++, key, value);
            if (size == 0)
            {
                if (tree.empty())
                    return;
                LFU.erase((*(tree.begin())).key);
                tree.erase(tree.begin());
            }
            else
            {
                size--;
            }
            LFU.insert(make_pair(key, newNode));
            tree.insert(newNode);
        }
        else
        {
            unordered_map<int, Node>::iterator iter = LFU.find(key);
            Node now = (*iter).second;
            tree.erase(now);
            now.cnt++;
            now.time = time++;
            now.val = value;
            tree.insert(now);
            (*iter).second = now;
        }
    }
};
```

### B
```cpp
class LFUCache
{
public:
    LFUCache(int capacity_)
        : capacity(capacity_),
          minfreq(0)
    {
        iter_table.clear();
        freq_table.clear();
    }

    int get(int key)
    {
        if (capacity == 0)
            return -1;
        auto it = iter_table.find(key);
        if (it == iter_table.end())
            return -1;
        list<Value>::iterator iter = it->second;

        int value = iter->value;
        int freq = iter->freq;
        Value new_node(key, value, freq + 1);

        freq_table[freq].erase(iter);
        if (freq_table[freq].size() == 0)
        {
            freq_table.erase(freq);
            if (minfreq == freq)
                minfreq += 1;
        }
        freq_table[freq + 1].push_front(new_node);
        iter_table[key] = freq_table[freq + 1].begin();
        return new_node.value;
    }

    void put(int key, int value)
    {
        if (capacity == 0)
            return;
        auto it = iter_table.find(key);
        if (it == iter_table.end())
        {

            if (iter_table.size() == capacity)
            {
                auto it2 = freq_table[minfreq].back();
                iter_table.erase(it2.key);
                freq_table[minfreq].pop_back();
                if (freq_table[minfreq].size() == 0)
                {
                    freq_table.erase(minfreq);
                }
            }
            freq_table[1].push_front(Value{key, value, 1});
            iter_table[key] = freq_table[1].begin();
            minfreq = 1;
        }
        else
        {
            list<Value>::iterator iter = it->second;

            int freq = iter->freq;
            Value new_node(iter->key, value, freq + 1);

            freq_table[iter->freq].erase(iter);

            if (freq_table[freq].size() == 0)
            {
                freq_table.erase(freq);
                if (minfreq == freq)
                    minfreq += 1;
            }
            freq_table[freq + 1].push_front(new_node);
            iter_table[key] = freq_table[freq + 1].begin();
        }
    }

private:
    struct Value
    {
        Value(int key_, int value_, int freq_)
            : key(key_),
              value(value_),
              freq(freq_) {}
        int key;
        int value;
        int freq;
    };
    int capacity;
    int minfreq;
    unordered_map<int, list<Value>::iterator> iter_table;
    unordered_map<int, list<Value>> freq_table;
};

```

### C
```cpp
struct Value
{
    Value(int count_, int time_, int key_, int value_)
        : count(count_),
          key(key_),
          value(value_),
          time(time_) {}
    bool operator<(const Value &a) const
    {
        return count == a.count ? time < a.time : count < a.count;
    }
    int key;
    int value;
    int count;
    int time;
};
class LFUCache
{
public:
    LFUCache(int capacity_)
        : capacity(capacity_),
          time(0) {}

    int get(int key)
    {
        if (capacity == 0)
            return -1;
        auto it = table.find(key);
        if (it == table.end())
            return -1;
        Value cache = it->second;
        judge.erase(cache);
        cache.count++;
        cache.time = ++time;
        judge.insert(cache);
        it->second = cache;
        return cache.value;
    }

    void put(int key, int value)
    {
        if (capacity == 0)
            return;
        auto it = table.find(key);
        if (it == table.end())
        {
            if (table.size() == capacity)
            {

                table.erase(judge.begin()->key);
                judge.erase(judge.begin());
            }
            Value put_(0, ++time, key, value);
            table.insert({key, put_});
            judge.insert(put_);
        }
        else
        {
            Value temp = it->second;
            judge.erase(temp);
            Value put_(++temp.count, ++time, key, value);
            it->second = put_;
            judge.insert(put_);
        }
    }

private:
    const int capacity;
    int time;
    unordered_map<int, Value> table;
    set<Value> judge;
};

```