[Leetcode] 432. All O`one Data Structure 解题报告

来源:互联网 发布:来自mac的照片怎么删除 编辑:程序博客网 时间:2024/06/10 01:52

题目

Implement a data structure supporting the following operations:

  1. Inc(Key) - Inserts a new key with value 1. Or increments an existing key by 1. Key is guaranteed to be a non-empty string.
  2. Dec(Key) - If Key's value is 1, remove it from the data structure. Otherwise decrements an existing key by 1. If the key does not exist, this function does nothing. Key is guaranteed to be a non-empty string.
  3. GetMaxKey() - Returns one of the keys with maximal value. If no element exists, return an empty string "".
  4. GetMinKey() - Returns one of the keys with minimal value. If no element exists, return an empty string "".

Challenge: Perform all these in O(1) time complexity.

思路

由于所有四个函数都需要O(1)的时间复杂度,所以肯定要用哈希表来做;不仅如此,我们还需要用list来保存所有的key,使得getMaxKey()和getMinKey()函数都可以在O(1)的时间复杂度之内完成。那么,哈希表就需要建立key和list中位置迭代器之间的映射。由于每个key还需要对应一个次数,所以list中还不能只放key,而且某个次数可能会对应多个key值,所以我们再次用哈希表来保存次数相同的所有key值。为此,我们需要建立一个新的Bucket结构体来保存次数以及出现该次数的集合keys。我们的思路是建立一个次数分层的结构(在list中体现分层思想),每层放相同次数的key值。例如:"A": 4, "B": 4, "C": 2, "D": 1,那么用我们设计的结构保存出来就是:
row0: val = 4, keys = {"A", "B"}
row1: val = 2, keys = {"C"}
row2: val = 1, keys = {"D"}

我们现在来分析如何实现inc函数。如果我们插入一个新的key,跟我们插入一个已经存在的key,情况是完全不一样的,那么我们就需要分情况来讨论:

- 如果我们插入一个新的key,那么由于该key没有出现过,所以加入后次数一定为1,那么就有两种情况了,如果list中没有val为1的这一行,那么我们需要插入该行,如果已经有了val为1的这行,我们直接将key加入集合keys中即可。
- 如果我们插入了一个已存在的key,那么由于个数增加了1个,所以该key值肯定不能在当前行继续待下去了,要往上升职啊,那么这里就有两种情况了,如果该key要升职到的那行不存在,我们需要手动添加那一行;如果那一行存在,我们之间将key加入集合keys中,记得都要将原来行中的key值删掉。

下面我们再来看dec函数如何实现,其实理解了上面的inc函数,那么dec函数也就没什么难度了:
- 如果我们要删除的key不存在,那么直接返回即可。
- 如果我们要删除的key存在,那么我们看其val值是否为1,如果为1的话,那么直接在keys中删除该key即可,然后还需要判断如果该key是集合中的唯一一个,那么该行也需要删除。如果key的次数val不为1的话,我们要考虑降级问题,跟之前的升职很类似,如果要降级的行不存在,我们手动添加上,如果存在,则直接将key值添加到keys集合中即可。

分析到这里,getMaxKey()和getMinKey()就很简单了:直接返回首层和尾层的key值即可。我的这个帖子参考了http://www.cnblogs.com/grandyang/p/6012229.html。

代码

class AllOne {public:    /** Initialize your data structure here. */    AllOne() {            }        /** Inserts a new key <Key> with value 1. Or increments an existing key by 1. */    void inc(string key) {        // If the key doesn't exist, insert it with value 0.        if (bucketOfKey.count(key) == 0) {                              bucketOfKey[key] = buckets.insert(buckets.begin(), {0, {key}});        }        // Insert the key in next bucket and update the lookup.          auto next = bucketOfKey[key], bucket = next++;              if (next == buckets.end() || next->value > bucket->value + 1) {            next = buckets.insert(next, {bucket->value + 1, {}});        }        next->keys.insert(key);        bucketOfKey[key] = next;        // Remove the key from its old bucket.        bucket->keys.erase(key);                                    if (bucket->keys.empty()) {            buckets.erase(bucket);        }    }        /** Decrements an existing key by 1. If Key's value is 1, remove it from the data structure. */    void dec(string key) {        // If the key doesn't exist, just leave.        if (!bucketOfKey.count(key)) {                                  return;        }        // Maybe insert the key in previous bucket and update the lookup.        auto prev = bucketOfKey[key], bucket = prev--;              bucketOfKey.erase(key);        if (bucket->value > 1) {            if (bucket == buckets.begin() || prev->value < bucket->value - 1) {                prev = buckets.insert(bucket, {bucket->value - 1, {}});            }            prev->keys.insert(key);            bucketOfKey[key] = prev;        }        // Remove the key from its old bucket.        bucket->keys.erase(key);                                    if (bucket->keys.empty()) {            buckets.erase(bucket);        }    }        /** Returns one of the keys with maximal value. */    string getMaxKey() {        return buckets.empty() ? "" : *(buckets.rbegin()->keys.begin());    }        /** Returns one of the keys with Minimal value. */    string getMinKey() {        return buckets.empty() ? "" : *(buckets.begin()->keys.begin());    }private:    struct Bucket {         int value;         unordered_set<string> keys;     };    list<Bucket> buckets;           // ordered    unordered_map<string, list<Bucket>::iterator> bucketOfKey;};/** * Your AllOne object will be instantiated and called as such: * AllOne obj = new AllOne(); * obj.inc(key); * obj.dec(key); * string param_3 = obj.getMaxKey(); * string param_4 = obj.getMinKey(); */

原创粉丝点击