-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathmain.cpp
More file actions
144 lines (128 loc) · 4.69 KB
/
main.cpp
File metadata and controls
144 lines (128 loc) · 4.69 KB
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
// Source: https://leetcode.com/problems/all-oone-data-structure
// Title: All O`one Data Structure
// Difficulty: Hard
// Author: Mu Yang <http://muyang.pro>
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Design a data structure to store the strings' count with the ability to return the strings with minimum and maximum counts.
//
// Implement the `AllOne` class:
//
// - `AllOne()` Initializes the object of the data structure.
// - `inc(String key)` Increments the count of the string `key` by `1`. If `key` does not exist in the data structure, insert it with count `1`.
// - `dec(String key)` Decrements the count of the string `key` by `1`. If the count of `key` is `0` after the decrement, remove it from the data structure. It is guaranteed that `key` exists in the data structure before the decrement.
// - `getMaxKey()` Returns one of the keys with the maximal count. If no element exists, return an empty string `""`.
// - `getMinKey()` Returns one of the keys with the minimum count. If no element exists, return an empty string `""`.
//
// **Note** that each function must run in `O(1)` average time complexity.
//
// **Example 1:**
//
// ```
// Input:
// ["AllOne", "inc", "inc", "getMaxKey", "getMinKey", "inc", "getMaxKey", "getMinKey"]
// [[], ["hello"], ["hello"], [], [], ["leet"], [], []]
//
// Output:
// [null, null, null, "hello", "hello", null, "hello", "leet"]
//
// Explanation:
// AllOne allOne = new AllOne();
// allOne.inc("hello");
// allOne.inc("hello");
// allOne.getMaxKey(); // return "hello"
// allOne.getMinKey(); // return "hello"
// allOne.inc("leet");
// allOne.getMaxKey(); // return "hello"
// allOne.getMinKey(); // return "leet"
// ```
//
// **Constraints:**
//
// - `1 <= key.length <= 10`
// - `key` consists of lowercase English letters.
// - It is guaranteed that for each call to `dec`, `key` is existing in the data structure.
// - At most `5 * 10^4`calls will be made to `inc`, `dec`, `getMaxKey`, and `getMinKey`.
//
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#include <iterator>
#include <list>
#include <unordered_map>
#include <unordered_set>
using namespace std;
// Hash Map + Hash Set + Linked List
//
// We use a linked list (sorted by frequency).
// Each node stores the frequency and the keys with this value.
// We also use a hash map to map the key to node.
//
// For `inc`, we move that key to the node with new frequency.
// If target node does not exist, insert it after this node.
// We also delete the old node if it becomes zero.
//
// Similary to `dec`.
// Hash Map + Hash Set + Linked List
//
// We use a linked list (sorted by frequency).
// Each node stores the frequency and the keys with this value.
// We also use a hash map to map the key to node.
//
// For `inc`, we move that key to the node with new frequency.
// If target node does not exist, insert it after this node.
// We also delete the old node if it becomes zero.
//
// Similary to `dec`.
class AllOne {
struct Data {
int freq;
unordered_set<string> keys;
Data(int freq) : freq(freq) {}
};
using List = list<Data>;
using Node = List::iterator;
unordered_map<string, Node> key2node;
List nodes;
public:
AllOne() {
nodes.push_back(Data{0}); // sentinel node for zero frequency
}
void inc(const string &key) {
// Find node
Node oldNode = key2node.contains(key) ? key2node[key] : nodes.begin();
Node newNode = next(oldNode); // next might not exist
if (newNode == nodes.cend() || newNode->freq > oldNode->freq + 1) {
newNode = nodes.insert(newNode, Data{oldNode->freq + 1});
}
// Update old node, avoid delete sentinel
oldNode->keys.erase(key);
if (oldNode != nodes.cbegin() && oldNode->keys.empty()) {
nodes.erase(oldNode);
}
// Update old node
newNode->keys.insert(key);
key2node[key] = newNode;
}
void dec(const string &key) {
// Find node
Node oldNode = key2node.at(key); // ensure existence
Node newNode = prev(oldNode); // prev exist since freq > 0
if (newNode->freq < oldNode->freq - 1) {
newNode = nodes.insert(oldNode, Data{oldNode->freq - 1});
}
// Update old node
oldNode->keys.erase(key);
if (oldNode->keys.empty()) nodes.erase(oldNode);
// Update new node
if (newNode->freq > 0) {
newNode->keys.insert(key);
key2node[key] = newNode;
} else {
key2node.erase(key);
}
}
string getMaxKey() { //
return key2node.empty() ? "" : prev(nodes.cend())->keys.cbegin()->data();
}
string getMinKey() { //
return key2node.empty() ? "" : next(nodes.cbegin())->keys.cbegin()->data();
}
};