-
Notifications
You must be signed in to change notification settings - Fork 4
/
Copy pathall-oone-data-structure.rs
executable file
·131 lines (122 loc) · 4.07 KB
/
all-oone-data-structure.rs
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
// 432. All O`one Data Structure
// 🔴 Hard
//
// https://leetcode.com/problems/all-oone-data-structure/
//
// Tags: Hash Table - Linked List - Design - Doubly-Linked List
use std::collections::{BTreeSet, HashMap};
/// We need to be able to find an entry given only its key, while at the same time, being able to
/// preserve the ordering of the entries based on their count, the easiest way is to use two data
/// structures, a hashmap of key => count to find the count of an item given its key, then use the
/// pair as the keys in a structure that preserves ordering, like a BTreeSet. For each call, we
/// remove the item from the set update its count and reinsert it, to preserve the ordering.
///
/// Time complexity: O(nlog(n)) - Where n is the number of calls made to inc/dec, these calls
/// remove the entry from the BTreeSet and reinsert it, both at log(n) cost.
/// Space complexity: O(e) - Where e is the number of different keys that are in the all-o-one
/// structure at one given time, and it could be equal to the number of calls.
///
/// Runtime 22 ms Beats 93%
/// Memory 14.80 MB Beats 62%
#[derive(Ord, PartialOrd, Eq, PartialEq)]
struct Entry {
count: usize,
key: String,
}
#[derive(Default)]
struct AllOne {
hm: HashMap<String, usize>,
counts: BTreeSet<Entry>,
}
/**
* `&self` means the method takes an immutable reference.
* If you need a mutable reference, change it to `&mut self` instead.
*/
impl AllOne {
fn new() -> Self {
Default::default()
}
fn inc(&mut self, key: String) {
match self.hm.get_mut(&key) {
Some(count) => {
let mut e = Entry { key, count: *count };
self.counts.remove(&e);
*count += 1;
e.count += 1;
self.counts.insert(e);
}
None => {
self.hm.insert(key.clone(), 1);
self.counts.insert(Entry { key, count: 1 });
}
}
}
#[allow(dead_code)]
fn dec(&mut self, key: String) {
match self.hm.get_mut(&key) {
Some(1) => {
self.hm.remove(&key);
self.counts.remove(&Entry { key, count: 1 });
}
Some(count) => {
let mut e = Entry { key, count: *count };
self.counts.remove(&e);
*count -= 1;
e.count -= 1;
self.counts.insert(e);
}
None => unreachable!("No calling dec with missing key"),
}
}
fn get_max_key(&self) -> String {
match self.counts.last() {
Some(e) => e.key.clone(),
None => "".to_string(),
}
}
fn get_min_key(&self) -> String {
match self.counts.first() {
Some(e) => e.key.clone(),
None => "".to_string(),
}
}
}
// Tests.
fn main() {
println!("\n\x1b[92m» Running tests...\x1b[0m");
let mut success = 0;
let mut all_one = AllOne::new();
all_one.inc("hello".to_string());
all_one.inc("hello".to_string());
if all_one.get_max_key() == "hello" {
println!("\x1b[92m✔\x1b[95m Test 1 passed!\x1b[0m");
success += 1;
}
if all_one.get_min_key() == "hello" {
println!("\x1b[92m✔\x1b[95m Test 2 passed!\x1b[0m");
success += 1;
}
all_one.inc("leet".to_string());
if all_one.get_max_key() == "hello" {
println!("\x1b[92m✔\x1b[95m Test 3 passed!\x1b[0m");
success += 1;
}
if all_one.get_min_key() == "leet" {
println!("\x1b[92m✔\x1b[95m Test 4 passed!\x1b[0m");
success += 1;
}
all_one.dec("hello".to_string());
all_one.dec("hello".to_string());
if all_one.get_max_key() == "leet" {
println!("\x1b[92m✔\x1b[95m Test 5 passed!\x1b[0m");
success += 1;
}
println!();
if success == 5 {
println!("\x1b[30;42m✔ All tests passed!\x1b[0m")
} else if success == 0 {
println!("\x1b[31mx \x1b[41;37mAll tests failed!\x1b[0m")
} else {
println!("\x1b[31mx\x1b[95m {} tests failed!\x1b[0m", 5 - success)
}
}