classRandomizedSet { public: /** Initialize your data structure here. */ unordered_map<int,int> m; vector<int> keys; RandomizedSet() {
} /** Inserts a value to the set. Returns true if the set did not already contain the specified element. */ boolinsert(int val){ if(m.find(val)!=m.end()) returnfalse; keys.push_back(val); m[val] = keys.size()-1; returntrue; } /** Removes a value from the set. Returns true if the set contained the specified element. */ boolremove(int val){ if(m.find(val)==m.end()) returnfalse; int temp = keys[keys.size()-1]; m[temp] = m[val]; keys[m[temp]] = temp; keys.pop_back(); m.erase(val); returntrue; } /** Get a random element from the set. */ intgetRandom(){ return keys[rand()%keys.size()]; } };
/** * Your RandomizedSet object will be instantiated and called as such: * RandomizedSet* obj = new RandomizedSet(); * bool param_1 = obj->insert(val); * bool param_2 = obj->remove(val); * int param_3 = obj->getRandom(); */
classRandomizedCollection { public: unordered_map<int,unordered_set<int>> m; vector<int> keys;
/** Initialize your data structure here. */ RandomizedCollection() {
} /** Inserts a value to the collection. Returns true if the collection did not already contain the specified element. */ boolinsert(int val){ keys.push_back(val); if(m.find(val)==m.end()){ m[val].emplace(int(keys.size()-1)); returntrue; }else{ m[val].emplace(int(keys.size()-1)); returnfalse; } } /** Removes a value from the collection. Returns true if the collection contained the specified element. */ boolremove(int val){ if(m.find(val)==m.end()) returnfalse; //取得最后一个key对应的下标end,要删除的元素所有下标的第一个 int end = keys.size() - 1; int idx = *m[val].begin(); //最后一个key赋值到要删除的位置上,并且最后一个key要删除end这个下标。 keys[idx] = keys.back(); m[keys[idx]].erase(end); //要删除的元素删除一个下标,如果是最后一个,就把元素从哈细表中删除。 m[val].erase(idx); if(m[val].empty()) m.erase(val); //如果删除元素的下标不是最后一个,就把删除的下标赋给原来最后一个key。 if(idx<end) m[keys[idx]].emplace(idx);
keys.pop_back(); returntrue; } /** Get a random element from the collection. */ intgetRandom(){ return keys[rand()%keys.size()]; } };
/** * Your RandomizedCollection object will be instantiated and called as such: * RandomizedCollection* obj = new RandomizedCollection(); * bool param_1 = obj->insert(val); * bool param_2 = obj->remove(val); * int param_3 = obj->getRandom(); */
对于「数位 DP」题,都存在「询问 [ a , b ] [a, b] [a,b]( a a a 和 b b b 均为正整数,且 a < b a < b a<b)区间内符合条件的数值个数为多少」的一般形式,通常我们需要实现一个查询 [ 0 , x ] [0, x] [0,x] 有多少合法数值的函数 int dp(int x),然后应用「容斥原理」求解出 [ a , b ] [a, b] [a,b] 的个数: d p ( b ) − d p ( a − 1 ) dp(b) - dp(a - 1) dp(b)−dp(a−1)。 对于本题,虽然只需要求解 [ 0 , n ] [0, n] [0,n] 范围内数的个数,但其实拓展到求 [ a , b ] [a, b] [a,b] 区间个数的也不会增加难度。
具体的,对于「数位 DP」问题通常是「从高位到低位」的分情况讨论。
不失一般性的考虑数值 n n n 的某一位 c u r cur cur 是如何被处理的:
如果当前位 c u r = 1 cur = 1 cur=1 的话,由于我们需要满足「小于等于 n n n」的要求,因此如果该位填 0 0 0 的话,后面的低位填什么都是满足要求的,因此我们期望能够查表得出「长度为 i + 1 i + 1 i+1,且二进制位置 i i i 数值为 0 0 0 时」有多少合法数值,将其累加到答案中; 与此同时,我们需要确保当前位选 1 1 1 是合法的,即我们需要记录上一位 p r e v prev prev 是什么,确保 c u r cur cur 和 p r e v prev prev 不同时为 1 1 1。
如果当前位 c u r = 0 cur = 0 cur=0 的话,我们只能选 0 0 0,并决策下一位。
当出现「当前位无法填入 c u r cur cur」或者「决策到最低位」时,则完成了所有合法答案的统计。
至于流程 1 1 1 中的查表操作,我们可以使用 static 预处理出 f 数组,定义 f [ i ] [ j ] f[i][j] f[i][j] 为考虑二进制长度为 i i i,且最高位为 j j j( 0 0 0 or 1 1 1)时的合法数个数。
注意:为了防止重复计数问题,我们在不失一般性的计算 f [ i ] [ 0 ] f[i][0] f[i][0] 和 f [ i ] [ 1 ] f[i][1] f[i][1] 时,不能采用诸如 f [ i ] [ c u r ] + = f [ i − 1 ] [ p r e v ] f[i][cur] += f[i - 1][prev] f[i][cur]+=f[i−1][prev] 的 “后向查找依赖” 的方式进行转移,而要采用 f [ i + 1 ] [ c u r ] + = f [ i ] [ p r e v ] f[i + 1][cur] += f[i][prev] f[i+1][cur]+=f[i][prev] “前向主动更新” 的方式进行转移。
不失一般性的考虑 f [ i ] [ 0 ] f[i][0] f[i][0] 和 f [ i ] [ 1 ] f[i][1] f[i][1] 能够更新哪些状态: