diff --git a/solution/2300-2399/2336.Smallest Number in Infinite Set/README.md b/solution/2300-2399/2336.Smallest Number in Infinite Set/README.md index 2f223bf9e7605..e9afb946cb806 100644 --- a/solution/2300-2399/2336.Smallest Number in Infinite Set/README.md +++ b/solution/2300-2399/2336.Smallest Number in Infinite Set/README.md @@ -51,54 +51,44 @@ smallestInfiniteSet.popSmallest(); // 返回 5 ,并将其从集合中移除。 -**方法一:哈希表** +**方法一:有序集合 + 模拟** -**方法二:哈希表 + 优先队列(小根堆)** +我们注意到,题目中集合的元素范围是 $[1, 1000]$,并且我们需要支持的操作有: - +- `popSmallest`:弹出集合中的最小元素 +- `addBack`:向集合中添加元素 -### **Python3** +因此,我们可以使用有序集合来模拟,不妨记有序集合为 $s$,集合中的元素为 $s_1, s_2, \cdots, s_n$,其中 $n$ 为有序集合中的元素个数。本题中 $n \le 1000$。 - +我们在初始化时,将 $[1, 1000]$ 中的所有元素加入有序集合中。时间复杂度 $O(n \times \log n)$。 -```python -class SmallestInfiniteSet: - def __init__(self): - self.black = set() +在 `popSmallest` 操作中,我们只需要弹出有序集合中的第一个元素即可。单次操作时间复杂度 $O(\log n)$。 - def popSmallest(self) -> int: - i = 1 - while i in self.black: - i += 1 - self.black.add(i) - return i +在 `addBack` 操作中,我们只需要将元素加入有序集合中即可。单次操作时间复杂度 $O(\log n)$。 - def addBack(self, num: int) -> None: - self.black.discard(num) +空间复杂度 $O(n)$。 + -# Your SmallestInfiniteSet object will be instantiated and called as such: -# obj = SmallestInfiniteSet() -# param_1 = obj.popSmallest() -# obj.addBack(num) -``` +### **Python3** + + ```python +from sortedcontainers import SortedSet + + class SmallestInfiniteSet: def __init__(self): - self.h = list(range(1, 1010)) - self.s = set(self.h) - heapify(self.h) + self.s = SortedSet(range(1, 1001)) def popSmallest(self) -> int: - ans = heappop(self.h) - self.s.discard(ans) - return ans + x = self.s[0] + self.s.remove(x) + return x def addBack(self, num: int) -> None: - if num not in self.s: - self.s.add(num) - heappush(self.h, num) + self.s.add(num) # Your SmallestInfiniteSet object will be instantiated and called as such: @@ -113,55 +103,20 @@ class SmallestInfiniteSet: ```java class SmallestInfiniteSet { - private Set black = new HashSet<>(); + private TreeSet s = new TreeSet<>(); public SmallestInfiniteSet() { - } - - public int popSmallest() { - int i = 1; - for (; black.contains(i); ++i) - ; - black.add(i); - return i; - } - - public void addBack(int num) { - black.remove(num); - } -} - -/** - * Your SmallestInfiniteSet object will be instantiated and called as such: - * SmallestInfiniteSet obj = new SmallestInfiniteSet(); - * int param_1 = obj.popSmallest(); - * obj.addBack(num); - */ -``` - -```java -class SmallestInfiniteSet { - private PriorityQueue pq = new PriorityQueue<>(); - private Set s = new HashSet<>(); - - public SmallestInfiniteSet() { - for (int i = 1; i < 1010; ++i) { - pq.offer(i); + for (int i = 1; i <= 1000; ++i) { s.add(i); } } public int popSmallest() { - int ans = pq.poll(); - s.remove(ans); - return ans; + return s.pollFirst(); } public void addBack(int num) { - if (!s.contains(num)) { - s.add(num); - pq.offer(num); - } + s.add(num); } } @@ -178,58 +133,24 @@ class SmallestInfiniteSet { ```cpp class SmallestInfiniteSet { public: - unordered_set black; - SmallestInfiniteSet() { - } - - int popSmallest() { - int i = 1; - for (; black.count(i); ++i) - ; - black.insert(i); - return i; - } - - void addBack(int num) { - black.erase(num); - } -}; - -/** - * Your SmallestInfiniteSet object will be instantiated and called as such: - * SmallestInfiniteSet* obj = new SmallestInfiniteSet(); - * int param_1 = obj->popSmallest(); - * obj->addBack(num); - */ -``` - -```cpp -class SmallestInfiniteSet { -public: - priority_queue, greater> pq; - unordered_set s; - - SmallestInfiniteSet() { - for (int i = 1; i < 1010; ++i) { - pq.push(i); + for (int i = 1; i <= 1000; ++i) { s.insert(i); } } int popSmallest() { - int ans = pq.top(); - pq.pop(); - s.erase(ans); - return ans; + int x = *s.begin(); + s.erase(s.begin()); + return x; } void addBack(int num) { - if (!s.count(num)) { - s.insert(num); - pq.push(num); - } + s.insert(num); } + +private: + set s; }; /** @@ -244,24 +165,25 @@ public: ```go type SmallestInfiniteSet struct { - black map[int]bool + s *treemap.Map } func Constructor() SmallestInfiniteSet { - s := map[int]bool{} + s := treemap.NewWithIntComparator() + for i := 1; i <= 1000; i++ { + s.Put(i, nil) + } return SmallestInfiniteSet{s} } func (this *SmallestInfiniteSet) PopSmallest() int { - i := 1 - for ; this.black[i]; i++ { - } - this.black[i] = true - return i + x, _ := this.s.Min() + this.s.Remove(x.(int)) + return x.(int) } func (this *SmallestInfiniteSet) AddBack(num int) { - this.black[num] = false + this.s.Put(num, nil) } /** @@ -272,77 +194,700 @@ func (this *SmallestInfiniteSet) AddBack(num int) { */ ``` -```go -type SmallestInfiniteSet struct { - h *hp - s map[int]bool +### **TypeScript** + +```ts +class SmallestInfiniteSet { + private s: TreeSet; + + constructor() { + this.s = new TreeSet(); + for (let i = 1; i <= 1000; ++i) { + this.s.add(i); + } + } + + popSmallest(): number { + return this.s.shift()!; + } + + addBack(num: number): void { + this.s.add(num); + } } -func Constructor() SmallestInfiniteSet { - h := &hp{} - s := map[int]bool{} - for i := 1; i < 1010; i++ { - s[i] = true - h.push(i) - } - return SmallestInfiniteSet{h, s} +type Compare = (lhs: T, rhs: T) => number; + +class RBTreeNode { + data: T; + count: number; + left: RBTreeNode | null; + right: RBTreeNode | null; + parent: RBTreeNode | null; + color: number; + constructor(data: T) { + this.data = data; + this.left = this.right = this.parent = null; + this.color = 0; + this.count = 1; + } + + sibling(): RBTreeNode | null { + if (!this.parent) return null; // sibling null if no parent + return this.isOnLeft() ? this.parent.right : this.parent.left; + } + + isOnLeft(): boolean { + return this === this.parent!.left; + } + + hasRedChild(): boolean { + return ( + Boolean(this.left && this.left.color === 0) || + Boolean(this.right && this.right.color === 0) + ); + } } -func (this *SmallestInfiniteSet) PopSmallest() int { - ans := this.h.pop() - this.s[ans] = false - return ans +class RBTree { + root: RBTreeNode | null; + lt: (l: T, r: T) => boolean; + constructor(compare: Compare = (l: T, r: T) => (l < r ? -1 : l > r ? 1 : 0)) { + this.root = null; + this.lt = (l: T, r: T) => compare(l, r) < 0; + } + + rotateLeft(pt: RBTreeNode): void { + const right = pt.right!; + pt.right = right.left; + + if (pt.right) pt.right.parent = pt; + right.parent = pt.parent; + + if (!pt.parent) this.root = right; + else if (pt === pt.parent.left) pt.parent.left = right; + else pt.parent.right = right; + + right.left = pt; + pt.parent = right; + } + + rotateRight(pt: RBTreeNode): void { + const left = pt.left!; + pt.left = left.right; + + if (pt.left) pt.left.parent = pt; + left.parent = pt.parent; + + if (!pt.parent) this.root = left; + else if (pt === pt.parent.left) pt.parent.left = left; + else pt.parent.right = left; + + left.right = pt; + pt.parent = left; + } + + swapColor(p1: RBTreeNode, p2: RBTreeNode): void { + const tmp = p1.color; + p1.color = p2.color; + p2.color = tmp; + } + + swapData(p1: RBTreeNode, p2: RBTreeNode): void { + const tmp = p1.data; + p1.data = p2.data; + p2.data = tmp; + } + + fixAfterInsert(pt: RBTreeNode): void { + let parent = null; + let grandParent = null; + + while (pt !== this.root && pt.color !== 1 && pt.parent?.color === 0) { + parent = pt.parent; + grandParent = pt.parent.parent; + + /* Case : A + Parent of pt is left child of Grand-parent of pt */ + if (parent === grandParent?.left) { + const uncle = grandParent.right; + + /* Case : 1 + The uncle of pt is also red + Only Recoloring required */ + if (uncle && uncle.color === 0) { + grandParent.color = 0; + parent.color = 1; + uncle.color = 1; + pt = grandParent; + } else { + /* Case : 2 + pt is right child of its parent + Left-rotation required */ + if (pt === parent.right) { + this.rotateLeft(parent); + pt = parent; + parent = pt.parent; + } + + /* Case : 3 + pt is left child of its parent + Right-rotation required */ + this.rotateRight(grandParent); + this.swapColor(parent!, grandParent); + pt = parent!; + } + } else { + /* Case : B + Parent of pt is right child of Grand-parent of pt */ + const uncle = grandParent!.left; + + /* Case : 1 + The uncle of pt is also red + Only Recoloring required */ + if (uncle != null && uncle.color === 0) { + grandParent!.color = 0; + parent.color = 1; + uncle.color = 1; + pt = grandParent!; + } else { + /* Case : 2 + pt is left child of its parent + Right-rotation required */ + if (pt === parent.left) { + this.rotateRight(parent); + pt = parent; + parent = pt.parent; + } + + /* Case : 3 + pt is right child of its parent + Left-rotation required */ + this.rotateLeft(grandParent!); + this.swapColor(parent!, grandParent!); + pt = parent!; + } + } + } + this.root!.color = 1; + } + + delete(val: T): boolean { + const node = this.find(val); + if (!node) return false; + node.count--; + if (!node.count) this.deleteNode(node); + return true; + } + + deleteAll(val: T): boolean { + const node = this.find(val); + if (!node) return false; + this.deleteNode(node); + return true; + } + + deleteNode(v: RBTreeNode): void { + const u = BSTreplace(v); + + // True when u and v are both black + const uvBlack = (u === null || u.color === 1) && v.color === 1; + const parent = v.parent!; + + if (!u) { + // u is null therefore v is leaf + if (v === this.root) this.root = null; + // v is root, making root null + else { + if (uvBlack) { + // u and v both black + // v is leaf, fix double black at v + this.fixDoubleBlack(v); + } else { + // u or v is red + if (v.sibling()) { + // sibling is not null, make it red" + v.sibling()!.color = 0; + } + } + // delete v from the tree + if (v.isOnLeft()) parent.left = null; + else parent.right = null; + } + return; + } + + if (!v.left || !v.right) { + // v has 1 child + if (v === this.root) { + // v is root, assign the value of u to v, and delete u + v.data = u.data; + v.left = v.right = null; + } else { + // Detach v from tree and move u up + if (v.isOnLeft()) parent.left = u; + else parent.right = u; + u.parent = parent; + if (uvBlack) this.fixDoubleBlack(u); + // u and v both black, fix double black at u + else u.color = 1; // u or v red, color u black + } + return; + } + + // v has 2 children, swap data with successor and recurse + this.swapData(u, v); + this.deleteNode(u); + + // find node that replaces a deleted node in BST + function BSTreplace(x: RBTreeNode): RBTreeNode | null { + // when node have 2 children + if (x.left && x.right) return successor(x.right); + // when leaf + if (!x.left && !x.right) return null; + // when single child + return x.left ?? x.right; + } + // find node that do not have a left child + // in the subtree of the given node + function successor(x: RBTreeNode): RBTreeNode { + let temp = x; + while (temp.left) temp = temp.left; + return temp; + } + } + + fixDoubleBlack(x: RBTreeNode): void { + if (x === this.root) return; // Reached root + + const sibling = x.sibling(); + const parent = x.parent!; + if (!sibling) { + // No sibiling, double black pushed up + this.fixDoubleBlack(parent); + } else { + if (sibling.color === 0) { + // Sibling red + parent.color = 0; + sibling.color = 1; + if (sibling.isOnLeft()) this.rotateRight(parent); + // left case + else this.rotateLeft(parent); // right case + this.fixDoubleBlack(x); + } else { + // Sibling black + if (sibling.hasRedChild()) { + // at least 1 red children + if (sibling.left && sibling.left.color === 0) { + if (sibling.isOnLeft()) { + // left left + sibling.left.color = sibling.color; + sibling.color = parent.color; + this.rotateRight(parent); + } else { + // right left + sibling.left.color = parent.color; + this.rotateRight(sibling); + this.rotateLeft(parent); + } + } else { + if (sibling.isOnLeft()) { + // left right + sibling.right!.color = parent.color; + this.rotateLeft(sibling); + this.rotateRight(parent); + } else { + // right right + sibling.right!.color = sibling.color; + sibling.color = parent.color; + this.rotateLeft(parent); + } + } + parent.color = 1; + } else { + // 2 black children + sibling.color = 0; + if (parent.color === 1) this.fixDoubleBlack(parent); + else parent.color = 1; + } + } + } + } + + insert(data: T): boolean { + // search for a position to insert + let parent = this.root; + while (parent) { + if (this.lt(data, parent.data)) { + if (!parent.left) break; + else parent = parent.left; + } else if (this.lt(parent.data, data)) { + if (!parent.right) break; + else parent = parent.right; + } else break; + } + + // insert node into parent + const node = new RBTreeNode(data); + if (!parent) this.root = node; + else if (this.lt(node.data, parent.data)) parent.left = node; + else if (this.lt(parent.data, node.data)) parent.right = node; + else { + parent.count++; + return false; + } + node.parent = parent; + this.fixAfterInsert(node); + return true; + } + + find(data: T): RBTreeNode | null { + let p = this.root; + while (p) { + if (this.lt(data, p.data)) { + p = p.left; + } else if (this.lt(p.data, data)) { + p = p.right; + } else break; + } + return p ?? null; + } + + *inOrder(root: RBTreeNode = this.root!): Generator { + if (!root) return; + for (const v of this.inOrder(root.left!)) yield v; + yield root.data; + for (const v of this.inOrder(root.right!)) yield v; + } + + *reverseInOrder(root: RBTreeNode = this.root!): Generator { + if (!root) return; + for (const v of this.reverseInOrder(root.right!)) yield v; + yield root.data; + for (const v of this.reverseInOrder(root.left!)) yield v; + } } -func (this *SmallestInfiniteSet) AddBack(num int) { - if !this.s[num] { - this.s[num] = true - this.h.push(num) - } +class TreeSet { + _size: number; + tree: RBTree; + compare: Compare; + constructor( + collection: T[] | Compare = [], + compare: Compare = (l: T, r: T) => (l < r ? -1 : l > r ? 1 : 0), + ) { + if (typeof collection === 'function') { + compare = collection; + collection = []; + } + this._size = 0; + this.compare = compare; + this.tree = new RBTree(compare); + for (const val of collection) this.add(val); + } + + size(): number { + return this._size; + } + + has(val: T): boolean { + return !!this.tree.find(val); + } + + add(val: T): boolean { + const successful = this.tree.insert(val); + this._size += successful ? 1 : 0; + return successful; + } + + delete(val: T): boolean { + const deleted = this.tree.deleteAll(val); + this._size -= deleted ? 1 : 0; + return deleted; + } + + ceil(val: T): T | undefined { + let p = this.tree.root; + let higher = null; + while (p) { + if (this.compare(p.data, val) >= 0) { + higher = p; + p = p.left; + } else { + p = p.right; + } + } + return higher?.data; + } + + floor(val: T): T | undefined { + let p = this.tree.root; + let lower = null; + while (p) { + if (this.compare(val, p.data) >= 0) { + lower = p; + p = p.right; + } else { + p = p.left; + } + } + return lower?.data; + } + + higher(val: T): T | undefined { + let p = this.tree.root; + let higher = null; + while (p) { + if (this.compare(val, p.data) < 0) { + higher = p; + p = p.left; + } else { + p = p.right; + } + } + return higher?.data; + } + + lower(val: T): T | undefined { + let p = this.tree.root; + let lower = null; + while (p) { + if (this.compare(p.data, val) < 0) { + lower = p; + p = p.right; + } else { + p = p.left; + } + } + return lower?.data; + } + + first(): T | undefined { + return this.tree.inOrder().next().value; + } + + last(): T | undefined { + return this.tree.reverseInOrder().next().value; + } + + shift(): T | undefined { + const first = this.first(); + if (first === undefined) return undefined; + this.delete(first); + return first; + } + + pop(): T | undefined { + const last = this.last(); + if (last === undefined) return undefined; + this.delete(last); + return last; + } + + *[Symbol.iterator](): Generator { + for (const val of this.values()) yield val; + } + + *keys(): Generator { + for (const val of this.values()) yield val; + } + + *values(): Generator { + for (const val of this.tree.inOrder()) yield val; + return undefined; + } + + /** + * Return a generator for reverse order traversing the set + */ + *rvalues(): Generator { + for (const val of this.tree.reverseInOrder()) yield val; + return undefined; + } } -type hp []int +class TreeMultiSet { + _size: number; + tree: RBTree; + compare: Compare; + constructor( + collection: T[] | Compare = [], + compare: Compare = (l: T, r: T) => (l < r ? -1 : l > r ? 1 : 0), + ) { + if (typeof collection === 'function') { + compare = collection; + collection = []; + } + this._size = 0; + this.compare = compare; + this.tree = new RBTree(compare); + for (const val of collection) this.add(val); + } + + size(): number { + return this._size; + } + + has(val: T): boolean { + return !!this.tree.find(val); + } + + add(val: T): boolean { + const successful = this.tree.insert(val); + this._size++; + return successful; + } + + delete(val: T): boolean { + const successful = this.tree.delete(val); + if (!successful) return false; + this._size--; + return true; + } + + count(val: T): number { + const node = this.tree.find(val); + return node ? node.count : 0; + } + + ceil(val: T): T | undefined { + let p = this.tree.root; + let higher = null; + while (p) { + if (this.compare(p.data, val) >= 0) { + higher = p; + p = p.left; + } else { + p = p.right; + } + } + return higher?.data; + } + + floor(val: T): T | undefined { + let p = this.tree.root; + let lower = null; + while (p) { + if (this.compare(val, p.data) >= 0) { + lower = p; + p = p.right; + } else { + p = p.left; + } + } + return lower?.data; + } + + higher(val: T): T | undefined { + let p = this.tree.root; + let higher = null; + while (p) { + if (this.compare(val, p.data) < 0) { + higher = p; + p = p.left; + } else { + p = p.right; + } + } + return higher?.data; + } + + lower(val: T): T | undefined { + let p = this.tree.root; + let lower = null; + while (p) { + if (this.compare(p.data, val) < 0) { + lower = p; + p = p.right; + } else { + p = p.left; + } + } + return lower?.data; + } + + first(): T | undefined { + return this.tree.inOrder().next().value; + } + + last(): T | undefined { + return this.tree.reverseInOrder().next().value; + } + + shift(): T | undefined { + const first = this.first(); + if (first === undefined) return undefined; + this.delete(first); + return first; + } + + pop(): T | undefined { + const last = this.last(); + if (last === undefined) return undefined; + this.delete(last); + return last; + } + + *[Symbol.iterator](): Generator { + yield* this.values(); + } + + *keys(): Generator { + for (const val of this.values()) yield val; + } + + *values(): Generator { + for (const val of this.tree.inOrder()) { + let count = this.count(val); + while (count--) yield val; + } + return undefined; + } -func (h hp) Len() int { return len(h) } -func (h hp) Less(i, j int) bool { return h[i] < h[j] } -func (h hp) Swap(i, j int) { h[i], h[j] = h[j], h[i] } -func (h *hp) Push(v any) { *h = append(*h, v.(int)) } -func (h *hp) Pop() (v any) { a := *h; *h, v = a[:len(a)-1], a[len(a)-1]; return } -func (h *hp) push(v int) { heap.Push(h, v) } -func (h *hp) pop() int { return heap.Pop(h).(int) } -func (h *hp) top() int { a := *h; return a[0] } + /** + * Return a generator for reverse order traversing the multi-set + */ + *rvalues(): Generator { + for (const val of this.tree.reverseInOrder()) { + let count = this.count(val); + while (count--) yield val; + } + return undefined; + } +} /** * Your SmallestInfiniteSet object will be instantiated and called as such: - * obj := Constructor(); - * param_1 := obj.PopSmallest(); - * obj.AddBack(num); + * var obj = new SmallestInfiniteSet() + * var param_1 = obj.popSmallest() + * obj.addBack(num) */ ``` -### **TypeScript** - ```ts class SmallestInfiniteSet { - private hashMap: boolean[]; + private pq: typeof MinPriorityQueue; + private s: Set; constructor() { - this.hashMap = new Array(1001).fill(true); + this.pq = new MinPriorityQueue(); + this.s = new Set(); + for (let i = 1; i <= 1000; i++) { + this.pq.enqueue(i, i); + this.s.add(i); + } } popSmallest(): number { - for (let i = 1; i <= 1001; i++) { - if (this.hashMap[i]) { - this.hashMap[i] = false; - return i; - } - } - return -1; + const x = this.pq.dequeue()?.element; + this.s.delete(x); + return x; } addBack(num: number): void { - if (!this.hashMap[num]) { - this.hashMap[num] = true; + if (!this.s.has(num)) { + this.pq.enqueue(num, num); + this.s.add(num); } } } @@ -358,33 +903,29 @@ class SmallestInfiniteSet { ### **Rust** ```rust +use std::collections::BTreeSet; + struct SmallestInfiniteSet { - counter: [bool; 1000], + s: BTreeSet, } -/** - * `&self` means the method takes an immutable reference. - * If you need a mutable reference, change it to `&mut self` instead. - */ impl SmallestInfiniteSet { fn new() -> Self { - Self { - counter: [true; 1000], + let mut set = BTreeSet::new(); + for i in 1..=1000 { + set.insert(i); } + SmallestInfiniteSet { s: set } } fn pop_smallest(&mut self) -> i32 { - for i in 0..1000 { - if self.counter[i] { - self.counter[i] = false; - return (i as i32) + 1; - } - } - -1 + let x = *self.s.iter().next().unwrap(); + self.s.remove(&x); + x } fn add_back(&mut self, num: i32) { - self.counter[(num as usize) - 1] = true; + self.s.insert(num); } }/** * Your SmallestInfiniteSet object will be instantiated and called as such: diff --git a/solution/2300-2399/2336.Smallest Number in Infinite Set/README_EN.md b/solution/2300-2399/2336.Smallest Number in Infinite Set/README_EN.md index 1de1949cd77b6..067fa58ca8806 100644 --- a/solution/2300-2399/2336.Smallest Number in Infinite Set/README_EN.md +++ b/solution/2300-2399/2336.Smallest Number in Infinite Set/README_EN.md @@ -47,48 +47,42 @@ smallestInfiniteSet.popSmallest(); // return 5, and remove it from the set. ## Solutions - +**Solution 1: Ordered Set + Simulation** -### **Python3** +We note that the range of elements in the set given by the problem is $[1, 1000]$, and the operations we need to support are: -```python -class SmallestInfiniteSet: - def __init__(self): - self.black = set() +- `popSmallest`: Pop the smallest element from the set +- `addBack`: Add an element back to the set - def popSmallest(self) -> int: - i = 1 - while i in self.black: - i += 1 - self.black.add(i) - return i +Therefore, we can use an ordered set to simulate this. Let's denote the ordered set as $s$, and the elements in the set as $s_1, s_2, \cdots, s_n$, where $n$ is the number of elements in the ordered set. In this problem, $n \le 1000$. - def addBack(self, num: int) -> None: - self.black.discard(num) +During initialization, we add all elements in $[1, 1000]$ to the ordered set. The time complexity is $O(n \times \log n)$. +In the `popSmallest` operation, we just need to pop the first element from the ordered set. The time complexity for a single operation is $O(\log n)$. -# Your SmallestInfiniteSet object will be instantiated and called as such: -# obj = SmallestInfiniteSet() -# param_1 = obj.popSmallest() -# obj.addBack(num) -``` +In the `addBack` operation, we just need to add the element back to the ordered set. The time complexity for a single operation is $O(\log n)$. + +The space complexity is $O(n)$. + + + +### **Python3** ```python +from sortedcontainers import SortedSet + + class SmallestInfiniteSet: def __init__(self): - self.h = list(range(1, 1010)) - self.s = set(self.h) - heapify(self.h) + self.s = SortedSet(range(1, 1001)) def popSmallest(self) -> int: - ans = heappop(self.h) - self.s.discard(ans) - return ans + x = self.s[0] + self.s.remove(x) + return x def addBack(self, num: int) -> None: - if num not in self.s: - self.s.add(num) - heappush(self.h, num) + self.s.add(num) # Your SmallestInfiniteSet object will be instantiated and called as such: @@ -101,55 +95,20 @@ class SmallestInfiniteSet: ```java class SmallestInfiniteSet { - private Set black = new HashSet<>(); + private TreeSet s = new TreeSet<>(); public SmallestInfiniteSet() { - } - - public int popSmallest() { - int i = 1; - for (; black.contains(i); ++i) - ; - black.add(i); - return i; - } - - public void addBack(int num) { - black.remove(num); - } -} - -/** - * Your SmallestInfiniteSet object will be instantiated and called as such: - * SmallestInfiniteSet obj = new SmallestInfiniteSet(); - * int param_1 = obj.popSmallest(); - * obj.addBack(num); - */ -``` - -```java -class SmallestInfiniteSet { - private PriorityQueue pq = new PriorityQueue<>(); - private Set s = new HashSet<>(); - - public SmallestInfiniteSet() { - for (int i = 1; i < 1010; ++i) { - pq.offer(i); + for (int i = 1; i <= 1000; ++i) { s.add(i); } } public int popSmallest() { - int ans = pq.poll(); - s.remove(ans); - return ans; + return s.pollFirst(); } public void addBack(int num) { - if (!s.contains(num)) { - s.add(num); - pq.offer(num); - } + s.add(num); } } @@ -166,58 +125,24 @@ class SmallestInfiniteSet { ```cpp class SmallestInfiniteSet { public: - unordered_set black; - SmallestInfiniteSet() { - } - - int popSmallest() { - int i = 1; - for (; black.count(i); ++i) - ; - black.insert(i); - return i; - } - - void addBack(int num) { - black.erase(num); - } -}; - -/** - * Your SmallestInfiniteSet object will be instantiated and called as such: - * SmallestInfiniteSet* obj = new SmallestInfiniteSet(); - * int param_1 = obj->popSmallest(); - * obj->addBack(num); - */ -``` - -```cpp -class SmallestInfiniteSet { -public: - priority_queue, greater> pq; - unordered_set s; - - SmallestInfiniteSet() { - for (int i = 1; i < 1010; ++i) { - pq.push(i); + for (int i = 1; i <= 1000; ++i) { s.insert(i); } } int popSmallest() { - int ans = pq.top(); - pq.pop(); - s.erase(ans); - return ans; + int x = *s.begin(); + s.erase(s.begin()); + return x; } void addBack(int num) { - if (!s.count(num)) { - s.insert(num); - pq.push(num); - } + s.insert(num); } + +private: + set s; }; /** @@ -232,24 +157,25 @@ public: ```go type SmallestInfiniteSet struct { - black map[int]bool + s *treemap.Map } func Constructor() SmallestInfiniteSet { - s := map[int]bool{} + s := treemap.NewWithIntComparator() + for i := 1; i <= 1000; i++ { + s.Put(i, nil) + } return SmallestInfiniteSet{s} } func (this *SmallestInfiniteSet) PopSmallest() int { - i := 1 - for ; this.black[i]; i++ { - } - this.black[i] = true - return i + x, _ := this.s.Min() + this.s.Remove(x.(int)) + return x.(int) } func (this *SmallestInfiniteSet) AddBack(num int) { - this.black[num] = false + this.s.Put(num, nil) } /** @@ -260,77 +186,700 @@ func (this *SmallestInfiniteSet) AddBack(num int) { */ ``` -```go -type SmallestInfiniteSet struct { - h *hp - s map[int]bool +### **TypeScript** + +```ts +class SmallestInfiniteSet { + private s: TreeSet; + + constructor() { + this.s = new TreeSet(); + for (let i = 1; i <= 1000; ++i) { + this.s.add(i); + } + } + + popSmallest(): number { + return this.s.shift()!; + } + + addBack(num: number): void { + this.s.add(num); + } } -func Constructor() SmallestInfiniteSet { - h := &hp{} - s := map[int]bool{} - for i := 1; i < 1010; i++ { - s[i] = true - h.push(i) - } - return SmallestInfiniteSet{h, s} +type Compare = (lhs: T, rhs: T) => number; + +class RBTreeNode { + data: T; + count: number; + left: RBTreeNode | null; + right: RBTreeNode | null; + parent: RBTreeNode | null; + color: number; + constructor(data: T) { + this.data = data; + this.left = this.right = this.parent = null; + this.color = 0; + this.count = 1; + } + + sibling(): RBTreeNode | null { + if (!this.parent) return null; // sibling null if no parent + return this.isOnLeft() ? this.parent.right : this.parent.left; + } + + isOnLeft(): boolean { + return this === this.parent!.left; + } + + hasRedChild(): boolean { + return ( + Boolean(this.left && this.left.color === 0) || + Boolean(this.right && this.right.color === 0) + ); + } } -func (this *SmallestInfiniteSet) PopSmallest() int { - ans := this.h.pop() - this.s[ans] = false - return ans +class RBTree { + root: RBTreeNode | null; + lt: (l: T, r: T) => boolean; + constructor(compare: Compare = (l: T, r: T) => (l < r ? -1 : l > r ? 1 : 0)) { + this.root = null; + this.lt = (l: T, r: T) => compare(l, r) < 0; + } + + rotateLeft(pt: RBTreeNode): void { + const right = pt.right!; + pt.right = right.left; + + if (pt.right) pt.right.parent = pt; + right.parent = pt.parent; + + if (!pt.parent) this.root = right; + else if (pt === pt.parent.left) pt.parent.left = right; + else pt.parent.right = right; + + right.left = pt; + pt.parent = right; + } + + rotateRight(pt: RBTreeNode): void { + const left = pt.left!; + pt.left = left.right; + + if (pt.left) pt.left.parent = pt; + left.parent = pt.parent; + + if (!pt.parent) this.root = left; + else if (pt === pt.parent.left) pt.parent.left = left; + else pt.parent.right = left; + + left.right = pt; + pt.parent = left; + } + + swapColor(p1: RBTreeNode, p2: RBTreeNode): void { + const tmp = p1.color; + p1.color = p2.color; + p2.color = tmp; + } + + swapData(p1: RBTreeNode, p2: RBTreeNode): void { + const tmp = p1.data; + p1.data = p2.data; + p2.data = tmp; + } + + fixAfterInsert(pt: RBTreeNode): void { + let parent = null; + let grandParent = null; + + while (pt !== this.root && pt.color !== 1 && pt.parent?.color === 0) { + parent = pt.parent; + grandParent = pt.parent.parent; + + /* Case : A + Parent of pt is left child of Grand-parent of pt */ + if (parent === grandParent?.left) { + const uncle = grandParent.right; + + /* Case : 1 + The uncle of pt is also red + Only Recoloring required */ + if (uncle && uncle.color === 0) { + grandParent.color = 0; + parent.color = 1; + uncle.color = 1; + pt = grandParent; + } else { + /* Case : 2 + pt is right child of its parent + Left-rotation required */ + if (pt === parent.right) { + this.rotateLeft(parent); + pt = parent; + parent = pt.parent; + } + + /* Case : 3 + pt is left child of its parent + Right-rotation required */ + this.rotateRight(grandParent); + this.swapColor(parent!, grandParent); + pt = parent!; + } + } else { + /* Case : B + Parent of pt is right child of Grand-parent of pt */ + const uncle = grandParent!.left; + + /* Case : 1 + The uncle of pt is also red + Only Recoloring required */ + if (uncle != null && uncle.color === 0) { + grandParent!.color = 0; + parent.color = 1; + uncle.color = 1; + pt = grandParent!; + } else { + /* Case : 2 + pt is left child of its parent + Right-rotation required */ + if (pt === parent.left) { + this.rotateRight(parent); + pt = parent; + parent = pt.parent; + } + + /* Case : 3 + pt is right child of its parent + Left-rotation required */ + this.rotateLeft(grandParent!); + this.swapColor(parent!, grandParent!); + pt = parent!; + } + } + } + this.root!.color = 1; + } + + delete(val: T): boolean { + const node = this.find(val); + if (!node) return false; + node.count--; + if (!node.count) this.deleteNode(node); + return true; + } + + deleteAll(val: T): boolean { + const node = this.find(val); + if (!node) return false; + this.deleteNode(node); + return true; + } + + deleteNode(v: RBTreeNode): void { + const u = BSTreplace(v); + + // True when u and v are both black + const uvBlack = (u === null || u.color === 1) && v.color === 1; + const parent = v.parent!; + + if (!u) { + // u is null therefore v is leaf + if (v === this.root) this.root = null; + // v is root, making root null + else { + if (uvBlack) { + // u and v both black + // v is leaf, fix double black at v + this.fixDoubleBlack(v); + } else { + // u or v is red + if (v.sibling()) { + // sibling is not null, make it red" + v.sibling()!.color = 0; + } + } + // delete v from the tree + if (v.isOnLeft()) parent.left = null; + else parent.right = null; + } + return; + } + + if (!v.left || !v.right) { + // v has 1 child + if (v === this.root) { + // v is root, assign the value of u to v, and delete u + v.data = u.data; + v.left = v.right = null; + } else { + // Detach v from tree and move u up + if (v.isOnLeft()) parent.left = u; + else parent.right = u; + u.parent = parent; + if (uvBlack) this.fixDoubleBlack(u); + // u and v both black, fix double black at u + else u.color = 1; // u or v red, color u black + } + return; + } + + // v has 2 children, swap data with successor and recurse + this.swapData(u, v); + this.deleteNode(u); + + // find node that replaces a deleted node in BST + function BSTreplace(x: RBTreeNode): RBTreeNode | null { + // when node have 2 children + if (x.left && x.right) return successor(x.right); + // when leaf + if (!x.left && !x.right) return null; + // when single child + return x.left ?? x.right; + } + // find node that do not have a left child + // in the subtree of the given node + function successor(x: RBTreeNode): RBTreeNode { + let temp = x; + while (temp.left) temp = temp.left; + return temp; + } + } + + fixDoubleBlack(x: RBTreeNode): void { + if (x === this.root) return; // Reached root + + const sibling = x.sibling(); + const parent = x.parent!; + if (!sibling) { + // No sibiling, double black pushed up + this.fixDoubleBlack(parent); + } else { + if (sibling.color === 0) { + // Sibling red + parent.color = 0; + sibling.color = 1; + if (sibling.isOnLeft()) this.rotateRight(parent); + // left case + else this.rotateLeft(parent); // right case + this.fixDoubleBlack(x); + } else { + // Sibling black + if (sibling.hasRedChild()) { + // at least 1 red children + if (sibling.left && sibling.left.color === 0) { + if (sibling.isOnLeft()) { + // left left + sibling.left.color = sibling.color; + sibling.color = parent.color; + this.rotateRight(parent); + } else { + // right left + sibling.left.color = parent.color; + this.rotateRight(sibling); + this.rotateLeft(parent); + } + } else { + if (sibling.isOnLeft()) { + // left right + sibling.right!.color = parent.color; + this.rotateLeft(sibling); + this.rotateRight(parent); + } else { + // right right + sibling.right!.color = sibling.color; + sibling.color = parent.color; + this.rotateLeft(parent); + } + } + parent.color = 1; + } else { + // 2 black children + sibling.color = 0; + if (parent.color === 1) this.fixDoubleBlack(parent); + else parent.color = 1; + } + } + } + } + + insert(data: T): boolean { + // search for a position to insert + let parent = this.root; + while (parent) { + if (this.lt(data, parent.data)) { + if (!parent.left) break; + else parent = parent.left; + } else if (this.lt(parent.data, data)) { + if (!parent.right) break; + else parent = parent.right; + } else break; + } + + // insert node into parent + const node = new RBTreeNode(data); + if (!parent) this.root = node; + else if (this.lt(node.data, parent.data)) parent.left = node; + else if (this.lt(parent.data, node.data)) parent.right = node; + else { + parent.count++; + return false; + } + node.parent = parent; + this.fixAfterInsert(node); + return true; + } + + find(data: T): RBTreeNode | null { + let p = this.root; + while (p) { + if (this.lt(data, p.data)) { + p = p.left; + } else if (this.lt(p.data, data)) { + p = p.right; + } else break; + } + return p ?? null; + } + + *inOrder(root: RBTreeNode = this.root!): Generator { + if (!root) return; + for (const v of this.inOrder(root.left!)) yield v; + yield root.data; + for (const v of this.inOrder(root.right!)) yield v; + } + + *reverseInOrder(root: RBTreeNode = this.root!): Generator { + if (!root) return; + for (const v of this.reverseInOrder(root.right!)) yield v; + yield root.data; + for (const v of this.reverseInOrder(root.left!)) yield v; + } } -func (this *SmallestInfiniteSet) AddBack(num int) { - if !this.s[num] { - this.s[num] = true - this.h.push(num) - } +class TreeSet { + _size: number; + tree: RBTree; + compare: Compare; + constructor( + collection: T[] | Compare = [], + compare: Compare = (l: T, r: T) => (l < r ? -1 : l > r ? 1 : 0), + ) { + if (typeof collection === 'function') { + compare = collection; + collection = []; + } + this._size = 0; + this.compare = compare; + this.tree = new RBTree(compare); + for (const val of collection) this.add(val); + } + + size(): number { + return this._size; + } + + has(val: T): boolean { + return !!this.tree.find(val); + } + + add(val: T): boolean { + const successful = this.tree.insert(val); + this._size += successful ? 1 : 0; + return successful; + } + + delete(val: T): boolean { + const deleted = this.tree.deleteAll(val); + this._size -= deleted ? 1 : 0; + return deleted; + } + + ceil(val: T): T | undefined { + let p = this.tree.root; + let higher = null; + while (p) { + if (this.compare(p.data, val) >= 0) { + higher = p; + p = p.left; + } else { + p = p.right; + } + } + return higher?.data; + } + + floor(val: T): T | undefined { + let p = this.tree.root; + let lower = null; + while (p) { + if (this.compare(val, p.data) >= 0) { + lower = p; + p = p.right; + } else { + p = p.left; + } + } + return lower?.data; + } + + higher(val: T): T | undefined { + let p = this.tree.root; + let higher = null; + while (p) { + if (this.compare(val, p.data) < 0) { + higher = p; + p = p.left; + } else { + p = p.right; + } + } + return higher?.data; + } + + lower(val: T): T | undefined { + let p = this.tree.root; + let lower = null; + while (p) { + if (this.compare(p.data, val) < 0) { + lower = p; + p = p.right; + } else { + p = p.left; + } + } + return lower?.data; + } + + first(): T | undefined { + return this.tree.inOrder().next().value; + } + + last(): T | undefined { + return this.tree.reverseInOrder().next().value; + } + + shift(): T | undefined { + const first = this.first(); + if (first === undefined) return undefined; + this.delete(first); + return first; + } + + pop(): T | undefined { + const last = this.last(); + if (last === undefined) return undefined; + this.delete(last); + return last; + } + + *[Symbol.iterator](): Generator { + for (const val of this.values()) yield val; + } + + *keys(): Generator { + for (const val of this.values()) yield val; + } + + *values(): Generator { + for (const val of this.tree.inOrder()) yield val; + return undefined; + } + + /** + * Return a generator for reverse order traversing the set + */ + *rvalues(): Generator { + for (const val of this.tree.reverseInOrder()) yield val; + return undefined; + } } -type hp []int +class TreeMultiSet { + _size: number; + tree: RBTree; + compare: Compare; + constructor( + collection: T[] | Compare = [], + compare: Compare = (l: T, r: T) => (l < r ? -1 : l > r ? 1 : 0), + ) { + if (typeof collection === 'function') { + compare = collection; + collection = []; + } + this._size = 0; + this.compare = compare; + this.tree = new RBTree(compare); + for (const val of collection) this.add(val); + } + + size(): number { + return this._size; + } + + has(val: T): boolean { + return !!this.tree.find(val); + } + + add(val: T): boolean { + const successful = this.tree.insert(val); + this._size++; + return successful; + } + + delete(val: T): boolean { + const successful = this.tree.delete(val); + if (!successful) return false; + this._size--; + return true; + } + + count(val: T): number { + const node = this.tree.find(val); + return node ? node.count : 0; + } + + ceil(val: T): T | undefined { + let p = this.tree.root; + let higher = null; + while (p) { + if (this.compare(p.data, val) >= 0) { + higher = p; + p = p.left; + } else { + p = p.right; + } + } + return higher?.data; + } + + floor(val: T): T | undefined { + let p = this.tree.root; + let lower = null; + while (p) { + if (this.compare(val, p.data) >= 0) { + lower = p; + p = p.right; + } else { + p = p.left; + } + } + return lower?.data; + } + + higher(val: T): T | undefined { + let p = this.tree.root; + let higher = null; + while (p) { + if (this.compare(val, p.data) < 0) { + higher = p; + p = p.left; + } else { + p = p.right; + } + } + return higher?.data; + } + + lower(val: T): T | undefined { + let p = this.tree.root; + let lower = null; + while (p) { + if (this.compare(p.data, val) < 0) { + lower = p; + p = p.right; + } else { + p = p.left; + } + } + return lower?.data; + } + + first(): T | undefined { + return this.tree.inOrder().next().value; + } + + last(): T | undefined { + return this.tree.reverseInOrder().next().value; + } + + shift(): T | undefined { + const first = this.first(); + if (first === undefined) return undefined; + this.delete(first); + return first; + } + + pop(): T | undefined { + const last = this.last(); + if (last === undefined) return undefined; + this.delete(last); + return last; + } + + *[Symbol.iterator](): Generator { + yield* this.values(); + } + + *keys(): Generator { + for (const val of this.values()) yield val; + } + + *values(): Generator { + for (const val of this.tree.inOrder()) { + let count = this.count(val); + while (count--) yield val; + } + return undefined; + } -func (h hp) Len() int { return len(h) } -func (h hp) Less(i, j int) bool { return h[i] < h[j] } -func (h hp) Swap(i, j int) { h[i], h[j] = h[j], h[i] } -func (h *hp) Push(v any) { *h = append(*h, v.(int)) } -func (h *hp) Pop() (v any) { a := *h; *h, v = a[:len(a)-1], a[len(a)-1]; return } -func (h *hp) push(v int) { heap.Push(h, v) } -func (h *hp) pop() int { return heap.Pop(h).(int) } -func (h *hp) top() int { a := *h; return a[0] } + /** + * Return a generator for reverse order traversing the multi-set + */ + *rvalues(): Generator { + for (const val of this.tree.reverseInOrder()) { + let count = this.count(val); + while (count--) yield val; + } + return undefined; + } +} /** * Your SmallestInfiniteSet object will be instantiated and called as such: - * obj := Constructor(); - * param_1 := obj.PopSmallest(); - * obj.AddBack(num); + * var obj = new SmallestInfiniteSet() + * var param_1 = obj.popSmallest() + * obj.addBack(num) */ ``` -### **TypeScript** - ```ts class SmallestInfiniteSet { - private hashMap: boolean[]; + private pq: typeof MinPriorityQueue; + private s: Set; constructor() { - this.hashMap = new Array(1001).fill(true); + this.pq = new MinPriorityQueue(); + this.s = new Set(); + for (let i = 1; i <= 1000; i++) { + this.pq.enqueue(i, i); + this.s.add(i); + } } popSmallest(): number { - for (let i = 1; i <= 1001; i++) { - if (this.hashMap[i]) { - this.hashMap[i] = false; - return i; - } - } - return -1; + const x = this.pq.dequeue()?.element; + this.s.delete(x); + return x; } addBack(num: number): void { - if (!this.hashMap[num]) { - this.hashMap[num] = true; + if (!this.s.has(num)) { + this.pq.enqueue(num, num); + this.s.add(num); } } } @@ -346,33 +895,29 @@ class SmallestInfiniteSet { ### **Rust** ```rust +use std::collections::BTreeSet; + struct SmallestInfiniteSet { - counter: [bool; 1000], + s: BTreeSet, } -/** - * `&self` means the method takes an immutable reference. - * If you need a mutable reference, change it to `&mut self` instead. - */ impl SmallestInfiniteSet { fn new() -> Self { - Self { - counter: [true; 1000], + let mut set = BTreeSet::new(); + for i in 1..=1000 { + set.insert(i); } + SmallestInfiniteSet { s: set } } fn pop_smallest(&mut self) -> i32 { - for i in 0..1000 { - if self.counter[i] { - self.counter[i] = false; - return (i as i32) + 1; - } - } - -1 + let x = *self.s.iter().next().unwrap(); + self.s.remove(&x); + x } fn add_back(&mut self, num: i32) { - self.counter[(num as usize) - 1] = true; + self.s.insert(num); } }/** * Your SmallestInfiniteSet object will be instantiated and called as such: diff --git a/solution/2300-2399/2336.Smallest Number in Infinite Set/Solution.cpp b/solution/2300-2399/2336.Smallest Number in Infinite Set/Solution.cpp index 223f10d9ac6de..e371130bb3422 100644 --- a/solution/2300-2399/2336.Smallest Number in Infinite Set/Solution.cpp +++ b/solution/2300-2399/2336.Smallest Number in Infinite Set/Solution.cpp @@ -1,26 +1,28 @@ -class SmallestInfiniteSet { -public: - unordered_set black; - - SmallestInfiniteSet() { - } - - int popSmallest() { - int i = 1; - for (; black.count(i); ++i) - ; - black.insert(i); - return i; - } - - void addBack(int num) { - black.erase(num); - } -}; - -/** - * Your SmallestInfiniteSet object will be instantiated and called as such: - * SmallestInfiniteSet* obj = new SmallestInfiniteSet(); - * int param_1 = obj->popSmallest(); - * obj->addBack(num); +class SmallestInfiniteSet { +public: + SmallestInfiniteSet() { + for (int i = 1; i <= 1000; ++i) { + s.insert(i); + } + } + + int popSmallest() { + int x = *s.begin(); + s.erase(s.begin()); + return x; + } + + void addBack(int num) { + s.insert(num); + } + +private: + set s; +}; + +/** + * Your SmallestInfiniteSet object will be instantiated and called as such: + * SmallestInfiniteSet* obj = new SmallestInfiniteSet(); + * int param_1 = obj->popSmallest(); + * obj->addBack(num); */ \ No newline at end of file diff --git a/solution/2300-2399/2336.Smallest Number in Infinite Set/Solution.go b/solution/2300-2399/2336.Smallest Number in Infinite Set/Solution.go index 79a49a8b7718f..7c2c89f070901 100644 --- a/solution/2300-2399/2336.Smallest Number in Infinite Set/Solution.go +++ b/solution/2300-2399/2336.Smallest Number in Infinite Set/Solution.go @@ -1,22 +1,23 @@ type SmallestInfiniteSet struct { - black map[int]bool + s *treemap.Map } func Constructor() SmallestInfiniteSet { - s := map[int]bool{} + s := treemap.NewWithIntComparator() + for i := 1; i <= 1000; i++ { + s.Put(i, nil) + } return SmallestInfiniteSet{s} } func (this *SmallestInfiniteSet) PopSmallest() int { - i := 1 - for ; this.black[i]; i++ { - } - this.black[i] = true - return i + x, _ := this.s.Min() + this.s.Remove(x.(int)) + return x.(int) } func (this *SmallestInfiniteSet) AddBack(num int) { - this.black[num] = false + this.s.Put(num, nil) } /** diff --git a/solution/2300-2399/2336.Smallest Number in Infinite Set/Solution.java b/solution/2300-2399/2336.Smallest Number in Infinite Set/Solution.java index bbd0769f8d6d5..3b6adca8cc209 100644 --- a/solution/2300-2399/2336.Smallest Number in Infinite Set/Solution.java +++ b/solution/2300-2399/2336.Smallest Number in Infinite Set/Solution.java @@ -1,25 +1,24 @@ -class SmallestInfiniteSet { - private Set black = new HashSet<>(); - - public SmallestInfiniteSet() { - } - - public int popSmallest() { - int i = 1; - for (; black.contains(i); ++i) - ; - black.add(i); - return i; - } - - public void addBack(int num) { - black.remove(num); - } -} - -/** - * Your SmallestInfiniteSet object will be instantiated and called as such: - * SmallestInfiniteSet obj = new SmallestInfiniteSet(); - * int param_1 = obj.popSmallest(); - * obj.addBack(num); +class SmallestInfiniteSet { + private TreeSet s = new TreeSet<>(); + + public SmallestInfiniteSet() { + for (int i = 1; i <= 1000; ++i) { + s.add(i); + } + } + + public int popSmallest() { + return s.pollFirst(); + } + + public void addBack(int num) { + s.add(num); + } +} + +/** + * Your SmallestInfiniteSet object will be instantiated and called as such: + * SmallestInfiniteSet obj = new SmallestInfiniteSet(); + * int param_1 = obj.popSmallest(); + * obj.addBack(num); */ \ No newline at end of file diff --git a/solution/2300-2399/2336.Smallest Number in Infinite Set/Solution.py b/solution/2300-2399/2336.Smallest Number in Infinite Set/Solution.py index e42a97e1444cd..cb78e926aa7c3 100644 --- a/solution/2300-2399/2336.Smallest Number in Infinite Set/Solution.py +++ b/solution/2300-2399/2336.Smallest Number in Infinite Set/Solution.py @@ -1,19 +1,20 @@ -class SmallestInfiniteSet: - def __init__(self): - self.black = set() - - def popSmallest(self) -> int: - i = 1 - while i in self.black: - i += 1 - self.black.add(i) - return i - - def addBack(self, num: int) -> None: - self.black.discard(num) - - -# Your SmallestInfiniteSet object will be instantiated and called as such: -# obj = SmallestInfiniteSet() -# param_1 = obj.popSmallest() -# obj.addBack(num) +from sortedcontainers import SortedSet + + +class SmallestInfiniteSet: + def __init__(self): + self.s = SortedSet(range(1, 1001)) + + def popSmallest(self) -> int: + x = self.s[0] + self.s.remove(x) + return x + + def addBack(self, num: int) -> None: + self.s.add(num) + + +# Your SmallestInfiniteSet object will be instantiated and called as such: +# obj = SmallestInfiniteSet() +# param_1 = obj.popSmallest() +# obj.addBack(num) diff --git a/solution/2300-2399/2336.Smallest Number in Infinite Set/Solution.rs b/solution/2300-2399/2336.Smallest Number in Infinite Set/Solution.rs index c7b1d5492c354..546e320d68304 100644 --- a/solution/2300-2399/2336.Smallest Number in Infinite Set/Solution.rs +++ b/solution/2300-2399/2336.Smallest Number in Infinite Set/Solution.rs @@ -1,30 +1,26 @@ +use std::collections::BTreeSet; + struct SmallestInfiniteSet { - counter: [bool; 1000], + s: BTreeSet, } -/** - * `&self` means the method takes an immutable reference. - * If you need a mutable reference, change it to `&mut self` instead. - */ impl SmallestInfiniteSet { fn new() -> Self { - Self { - counter: [true; 1000], + let mut set = BTreeSet::new(); + for i in 1..=1000 { + set.insert(i); } + SmallestInfiniteSet { s: set } } fn pop_smallest(&mut self) -> i32 { - for i in 0..1000 { - if self.counter[i] { - self.counter[i] = false; - return (i as i32) + 1; - } - } - -1 + let x = *self.s.iter().next().unwrap(); + self.s.remove(&x); + x } fn add_back(&mut self, num: i32) { - self.counter[(num as usize) - 1] = true; + self.s.insert(num); } }/** * Your SmallestInfiniteSet object will be instantiated and called as such: diff --git a/solution/2300-2399/2336.Smallest Number in Infinite Set/Solution.ts b/solution/2300-2399/2336.Smallest Number in Infinite Set/Solution.ts index 62c9135477c53..1643b51cff370 100644 --- a/solution/2300-2399/2336.Smallest Number in Infinite Set/Solution.ts +++ b/solution/2300-2399/2336.Smallest Number in Infinite Set/Solution.ts @@ -1,23 +1,26 @@ class SmallestInfiniteSet { - private hashMap: boolean[]; + private pq: typeof MinPriorityQueue; + private s: Set; constructor() { - this.hashMap = new Array(1001).fill(true); + this.pq = new MinPriorityQueue(); + this.s = new Set(); + for (let i = 1; i <= 1000; i++) { + this.pq.enqueue(i, i); + this.s.add(i); + } } popSmallest(): number { - for (let i = 1; i <= 1001; i++) { - if (this.hashMap[i]) { - this.hashMap[i] = false; - return i; - } - } - return -1; + const x = this.pq.dequeue()?.element; + this.s.delete(x); + return x; } addBack(num: number): void { - if (!this.hashMap[num]) { - this.hashMap[num] = true; + if (!this.s.has(num)) { + this.pq.enqueue(num, num); + this.s.add(num); } } }