diff --git a/solution/1400-1499/1488.Avoid Flood in The City/README.md b/solution/1400-1499/1488.Avoid Flood in The City/README.md index b1c04f5fd8b1e..a4c48e634caac 100644 --- a/solution/1400-1499/1488.Avoid Flood in The City/README.md +++ b/solution/1400-1499/1488.Avoid Flood in The City/README.md @@ -204,21 +204,24 @@ func avoidFlood(rains []int) []int { for i := range ans { ans[i] = -1 } - sunny := []int{} + + sunny := redblacktree.New[int, struct{}]() rainy := map[int]int{} + for i, v := range rains { if v > 0 { - if j, ok := rainy[v]; ok { - idx := sort.SearchInts(sunny, j+1) - if idx == len(sunny) { + if last, ok := rainy[v]; ok { + node, found := sunny.Ceiling(last + 1) + if !found { return []int{} } - ans[sunny[idx]] = v - sunny = append(sunny[:idx], sunny[idx+1:]...) + t := node.Key + ans[t] = v + sunny.Remove(t) } rainy[v] = i } else { - sunny = append(sunny, i) + sunny.Put(i, struct{}{}) ans[i] = 1 } } @@ -229,518 +232,64 @@ func avoidFlood(rains []int) []int { #### TypeScript ```ts +import { AvlTree } from 'datastructures-js'; + function avoidFlood(rains: number[]): number[] { const n = rains.length; - const ans: number[] = new Array(n).fill(-1); - const sunny: TreeSet = new TreeSet(); - const rainy: Map = new Map(); + const ans = Array(n).fill(-1); + const sunny = new AvlTree((a, b) => a - b); + const rainy = new Map(); + for (let i = 0; i < n; ++i) { const v = rains[i]; if (v > 0) { if (rainy.has(v)) { - const t = sunny.higher(rainy.get(v)!); - if (t === undefined) { - return []; - } + const last = rainy.get(v)!; + const node = sunny.ceil(last + 1); + if (!node) return []; + const t = node.getValue(); ans[t] = v; - sunny.delete(t); + sunny.remove(t); } rainy.set(v, i); } else { - sunny.add(i); + sunny.insert(i); ans[i] = 1; } } return ans; } +``` -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) - ); - } -} - -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; - } +#### Rust - 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; - } +```rust +use std::collections::{BTreeSet, HashMap}; - // 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 +impl Solution { + pub fn avoid_flood(rains: Vec) -> Vec { + let n = rains.len(); + let mut ans = vec![-1; n]; + let mut sunny = BTreeSet::new(); + let mut rainy = HashMap::new(); - 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); - } + for (i, &v) in rains.iter().enumerate() { + if v > 0 { + if let Some(&last) = rainy.get(&v) { + if let Some(&t) = sunny.range((last + 1) as usize..).next() { + ans[t] = v; + sunny.remove(&t); } 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); - } + return vec![]; } - 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; - } -} - -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; + rainy.insert(v, i as i32); } 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; + sunny.insert(i); + ans[i] = 1; } } - 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; + ans } } ``` diff --git a/solution/1400-1499/1488.Avoid Flood in The City/README_EN.md b/solution/1400-1499/1488.Avoid Flood in The City/README_EN.md index 0ba064d885617..f736e88cfa209 100644 --- a/solution/1400-1499/1488.Avoid Flood in The City/README_EN.md +++ b/solution/1400-1499/1488.Avoid Flood in The City/README_EN.md @@ -202,21 +202,24 @@ func avoidFlood(rains []int) []int { for i := range ans { ans[i] = -1 } - sunny := []int{} + + sunny := redblacktree.New[int, struct{}]() rainy := map[int]int{} + for i, v := range rains { if v > 0 { - if j, ok := rainy[v]; ok { - idx := sort.SearchInts(sunny, j+1) - if idx == len(sunny) { + if last, ok := rainy[v]; ok { + node, found := sunny.Ceiling(last + 1) + if !found { return []int{} } - ans[sunny[idx]] = v - sunny = append(sunny[:idx], sunny[idx+1:]...) + t := node.Key + ans[t] = v + sunny.Remove(t) } rainy[v] = i } else { - sunny = append(sunny, i) + sunny.Put(i, struct{}{}) ans[i] = 1 } } @@ -227,518 +230,64 @@ func avoidFlood(rains []int) []int { #### TypeScript ```ts +import { AvlTree } from 'datastructures-js'; + function avoidFlood(rains: number[]): number[] { const n = rains.length; - const ans: number[] = new Array(n).fill(-1); - const sunny: TreeSet = new TreeSet(); - const rainy: Map = new Map(); + const ans = Array(n).fill(-1); + const sunny = new AvlTree((a, b) => a - b); + const rainy = new Map(); + for (let i = 0; i < n; ++i) { const v = rains[i]; if (v > 0) { if (rainy.has(v)) { - const t = sunny.higher(rainy.get(v)!); - if (t === undefined) { - return []; - } + const last = rainy.get(v)!; + const node = sunny.ceil(last + 1); + if (!node) return []; + const t = node.getValue(); ans[t] = v; - sunny.delete(t); + sunny.remove(t); } rainy.set(v, i); } else { - sunny.add(i); + sunny.insert(i); ans[i] = 1; } } return ans; } +``` -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) - ); - } -} - -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; - } +#### Rust - 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; - } +```rust +use std::collections::{BTreeSet, HashMap}; - // 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 +impl Solution { + pub fn avoid_flood(rains: Vec) -> Vec { + let n = rains.len(); + let mut ans = vec![-1; n]; + let mut sunny = BTreeSet::new(); + let mut rainy = HashMap::new(); - 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); - } + for (i, &v) in rains.iter().enumerate() { + if v > 0 { + if let Some(&last) = rainy.get(&v) { + if let Some(&t) = sunny.range((last + 1) as usize..).next() { + ans[t] = v; + sunny.remove(&t); } 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); - } + return vec![]; } - 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; - } -} - -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; + rainy.insert(v, i as i32); } 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; + sunny.insert(i); + ans[i] = 1; } } - 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; + ans } } ``` diff --git a/solution/1400-1499/1488.Avoid Flood in The City/Solution.go b/solution/1400-1499/1488.Avoid Flood in The City/Solution.go index 3c0ebc14c2215..1de4afd297191 100644 --- a/solution/1400-1499/1488.Avoid Flood in The City/Solution.go +++ b/solution/1400-1499/1488.Avoid Flood in The City/Solution.go @@ -4,23 +4,26 @@ func avoidFlood(rains []int) []int { for i := range ans { ans[i] = -1 } - sunny := []int{} + + sunny := redblacktree.New[int, struct{}]() rainy := map[int]int{} + for i, v := range rains { if v > 0 { - if j, ok := rainy[v]; ok { - idx := sort.SearchInts(sunny, j+1) - if idx == len(sunny) { + if last, ok := rainy[v]; ok { + node, found := sunny.Ceiling(last + 1) + if !found { return []int{} } - ans[sunny[idx]] = v - sunny = append(sunny[:idx], sunny[idx+1:]...) + t := node.Key + ans[t] = v + sunny.Remove(t) } rainy[v] = i } else { - sunny = append(sunny, i) + sunny.Put(i, struct{}{}) ans[i] = 1 } } return ans -} \ No newline at end of file +} diff --git a/solution/1400-1499/1488.Avoid Flood in The City/Solution.rs b/solution/1400-1499/1488.Avoid Flood in The City/Solution.rs new file mode 100644 index 0000000000000..ee1566a1f7f28 --- /dev/null +++ b/solution/1400-1499/1488.Avoid Flood in The City/Solution.rs @@ -0,0 +1,28 @@ +use std::collections::{BTreeSet, HashMap}; + +impl Solution { + pub fn avoid_flood(rains: Vec) -> Vec { + let n = rains.len(); + let mut ans = vec![-1; n]; + let mut sunny = BTreeSet::new(); + let mut rainy = HashMap::new(); + + for (i, &v) in rains.iter().enumerate() { + if v > 0 { + if let Some(&last) = rainy.get(&v) { + if let Some(&t) = sunny.range((last + 1) as usize..).next() { + ans[t] = v; + sunny.remove(&t); + } else { + return vec![]; + } + } + rainy.insert(v, i as i32); + } else { + sunny.insert(i); + ans[i] = 1; + } + } + ans + } +} diff --git a/solution/1400-1499/1488.Avoid Flood in The City/Solution.ts b/solution/1400-1499/1488.Avoid Flood in The City/Solution.ts index b1154acededfb..e252742aede04 100644 --- a/solution/1400-1499/1488.Avoid Flood in The City/Solution.ts +++ b/solution/1400-1499/1488.Avoid Flood in The City/Solution.ts @@ -1,514 +1,27 @@ +import { AvlTree } from 'datastructures-js'; + function avoidFlood(rains: number[]): number[] { const n = rains.length; - const ans: number[] = new Array(n).fill(-1); - const sunny: TreeSet = new TreeSet(); - const rainy: Map = new Map(); + const ans = Array(n).fill(-1); + const sunny = new AvlTree((a, b) => a - b); + const rainy = new Map(); + for (let i = 0; i < n; ++i) { const v = rains[i]; if (v > 0) { if (rainy.has(v)) { - const t = sunny.higher(rainy.get(v)!); - if (t === undefined) { - return []; - } + const last = rainy.get(v)!; + const node = sunny.ceil(last + 1); + if (!node) return []; + const t = node.getValue(); ans[t] = v; - sunny.delete(t); + sunny.remove(t); } rainy.set(v, i); } else { - sunny.add(i); + sunny.insert(i); ans[i] = 1; } } return ans; } - -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) - ); - } -} - -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; - } -} - -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; - } -} diff --git a/solution/3700-3799/3703.Remove K-Balanced Substrings/README.md b/solution/3700-3799/3703.Remove K-Balanced Substrings/README.md index 5d909cc123514..16db410ca204f 100644 --- a/solution/3700-3799/3703.Remove K-Balanced Substrings/README.md +++ b/solution/3700-3799/3703.Remove K-Balanced Substrings/README.md @@ -207,7 +207,7 @@ class Solution { if (!stk.isEmpty() && stk.get(stk.size() - 1)[0] == c) { stk.get(stk.size() - 1)[1] += 1; } else { - stk.add(new int[]{c, 1}); + stk.add(new int[] {c, 1}); } if (c == ')' && stk.size() > 1) { int[] top = stk.get(stk.size() - 1); diff --git a/solution/3700-3799/3703.Remove K-Balanced Substrings/README_EN.md b/solution/3700-3799/3703.Remove K-Balanced Substrings/README_EN.md index be0c488d71f75..d9e0e3a606771 100644 --- a/solution/3700-3799/3703.Remove K-Balanced Substrings/README_EN.md +++ b/solution/3700-3799/3703.Remove K-Balanced Substrings/README_EN.md @@ -202,7 +202,7 @@ class Solution { if (!stk.isEmpty() && stk.get(stk.size() - 1)[0] == c) { stk.get(stk.size() - 1)[1] += 1; } else { - stk.add(new int[]{c, 1}); + stk.add(new int[] {c, 1}); } if (c == ')' && stk.size() > 1) { int[] top = stk.get(stk.size() - 1); diff --git a/solution/3700-3799/3703.Remove K-Balanced Substrings/Solution.java b/solution/3700-3799/3703.Remove K-Balanced Substrings/Solution.java index 1fab503ddca05..366fef271d984 100644 --- a/solution/3700-3799/3703.Remove K-Balanced Substrings/Solution.java +++ b/solution/3700-3799/3703.Remove K-Balanced Substrings/Solution.java @@ -5,7 +5,7 @@ public String removeSubstring(String s, int k) { if (!stk.isEmpty() && stk.get(stk.size() - 1)[0] == c) { stk.get(stk.size() - 1)[1] += 1; } else { - stk.add(new int[]{c, 1}); + stk.add(new int[] {c, 1}); } if (c == ')' && stk.size() > 1) { int[] top = stk.get(stk.size() - 1);