LeetCode:432 全O(1)的数据结构

 思路:

1、时间复杂度要求O(1),由key查询value操作必须用 hash table

2、getMax, getMin 操作要实现O(1)的复杂度,必须要用有序的 list/vector

3、inc, dec操作要实现O(1)的复杂度,必须要用有序的 list

实现方法:

hash table:key为string,映射为list的迭代器

list:每一个节点内容:value + {keys} (即,节点的int值,和指向该节点的key值的集合)

特点:

用到了C++ STL中的unordered_map, unordered_set, list多种容器和对应的操作, 对应的迭代器的操作。

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) {
        auto it = m.find(key); //查找key对应的链表中的节点的迭代器构成的:映射对 

        if(it == m.end()){ //如果key不在map m中   //bug1:查找key是否在map m中,应该与m.end()比较,而不是l.end()
            if(l.empty() || l.front().val != 1){ //链表中没有节点,或者头节点的val值不为1
                l.push_front({1, {key}});
            }
            else{ //链表头节点的val值为1
                l.front().keys.insert(key);      //bug2:l头节点的keys,少打了front()
            }
            m[key] = l.begin(); //让新的key映射到链表l的头节点的迭代器
            return;                             //bug3: 忘记了return,造成执行时出错 runtime error: member access within null pointer of type 'struct __node_type' (hashtable_policy.h)
        }

        auto lit = it->second; //得到hash对的value, 即list的迭代器
        auto nextlit = next(lit); //如果key对应链表中的某个节点的迭代器,取它的下一个节点的迭代器

        if(nextlit==l.end() || nextlit->val != (lit->val + 1)){
            nextlit = l.insert(nextlit, {lit->val+1, {}});//要插在原来lit的节点的下一个节点,所以insert第一个参数是nextlit.插入节点的迭代器返回给nextlit,也可以省略不写
        }
        nextlit -> keys.insert(key);
        m[key] = nextlit;

        //清除原来节点的key,m中的key的映射此时已经更新,不用再改
        lit->keys.erase(key);
        if(lit->keys.empty()) 
            l.erase(lit); //如果这个节点已经没有key映射到,在链表中清除该节点
    }
    
    /** Decrements an existing key by 1. If Key's value is 1, remove it from the data structure. */
    void dec(string key) {
        auto it = m.find(key);
        if(it == m.end()) return; //找不到key对应的节点,无法执行val减一操作,直接返回

        auto lit = it->second;
        auto prelit = prev(lit);

        if(lit->val > 1){
            if(lit == l.begin() || (lit->val-1 != prelit->val)){
                prelit = l.insert(lit, {lit->val-1, {}}); // bug 4:插入位置错误.,在prelit之后、lit之前插入.insert()插入的元素会出现在lit之前
            }
            prelit->keys.insert(key);
            m[key] = prelit;
        }
        else{
            // 如果val == 1
            m.erase(key);
            //lit->keys.erase(key);
            //if(lit->keys.empty())
            //    l.erase(lit);            
        }

        lit->keys.erase(key);
        if(lit->keys.empty())
            l.erase(lit);
    }
    
    /** Returns one of the keys with maximal value. */
    string getMaxKey() {
        return l.empty()? "" : *l.back().keys.cbegin();
    }
    
    /** Returns one of the keys with Minimal value. */
    string getMinKey() {
        return l.empty()? "" : *l.front().keys.cbegin();
    }

private:
    struct Node {
        int val;
        unordered_set<string> keys; //该节点中val对应的key的集合,也就是指向该节点的key的集合
    };
    list<Node> l;
    //unordered_map<string, Node> m;
    unordered_map<string, list<Node>::iterator> m; //哈希表的key映射为链表中的某个节点的迭代器,以实现O(1)时间访问链表中某节点
};

/**
 * 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();
 */
发布了97 篇原创文章 · 获赞 11 · 访问量 2494

猜你喜欢

转载自blog.csdn.net/chengda321/article/details/102567607