Skip to content

Commit abaaa1f

Browse files
author
hasibulislam999
committed
Sequentially Ordinal Rank Tracker problem solved
1 parent 3f199ec commit abaaa1f

File tree

1 file changed

+333
-0
lines changed

1 file changed

+333
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,333 @@
1+
/**
2+
* Title: Sequentially Ordinal Rank Tracker
3+
* Description: A scenic location is represented by its name and attractiveness score, where name is a unique string among all locations and score is an integer. Locations can be ranked from the best to the worst. The higher the score, the better the location. If the scores of two locations are equal, then the location with the lexicographically smaller name is better.
4+
* Author: Hasibul Islam
5+
* Date: 28/04/2023
6+
*/
7+
8+
class AVLNode {
9+
constructor(val) {
10+
this.val = val;
11+
this.left = null;
12+
this.right = null;
13+
this.height = 1;
14+
this.cnt = 1;
15+
this.SubTreeNodes = 1;
16+
}
17+
}
18+
19+
const lexical_smallest_comp = (x, y) => (x < y ? -1 : x > y ? 1 : 0);
20+
21+
class AVLTree {
22+
constructor() {
23+
this.root = null;
24+
this.nodeCount = 0;
25+
this.tot = 0;
26+
}
27+
cmp(x, y) {
28+
// compare nodes: x is inserted item
29+
if (x == null || y == null) return 0;
30+
if (Array.isArray(x) || Number.isInteger(x)) x = new AVLNode(x);
31+
if (Array.isArray(y) || Number.isInteger(y)) y = new AVLNode(y);
32+
if (Array.isArray(x.val) || Array.isArray(y.val)) {
33+
// array compare (can change like PQ)
34+
// this problem comparator
35+
if (Array.isArray(x.val) && Array.isArray(y.val)) {
36+
if (x.val[1] != y.val[1]) return y.val[1] - x.val[1]; // first priority: larger score comes first
37+
return lexical_smallest_comp(x.val[0], y.val[0]); // second priority: lexical smaller comes first
38+
} else {
39+
return 0;
40+
}
41+
} else if (Number.isInteger(x.val) || Number.isInteger(y.val)) {
42+
// number compare
43+
if (Number.isInteger(x.val) && Number.isInteger(y.val)) {
44+
return x.val - y.val;
45+
} else {
46+
return 0;
47+
}
48+
}
49+
return 0;
50+
}
51+
getHeight(node) {
52+
return node != null ? node.height : 0;
53+
}
54+
getBalance(node) {
55+
return node != null
56+
? this.getHeight(node.left) - this.getHeight(node.right)
57+
: 0;
58+
}
59+
update(node) {
60+
let leftHeight = this.getHeight(node.left),
61+
rightHeight = this.getHeight(node.right);
62+
node.height = 1 + Math.max(leftHeight, rightHeight);
63+
node.SubTreeNodes =
64+
1 +
65+
(node.left != null ? node.left.SubTreeNodes : 0) +
66+
(node.right != null ? node.right.SubTreeNodes : 0);
67+
}
68+
LR(z) {
69+
let y = z.right;
70+
let T2 = y.left;
71+
y.left = z;
72+
z.right = T2;
73+
this.update(z);
74+
this.update(y);
75+
return y;
76+
}
77+
RR(z) {
78+
let y = z.left;
79+
let T3 = y.right;
80+
y.right = z;
81+
z.left = T3;
82+
this.update(z);
83+
this.update(y);
84+
return y;
85+
}
86+
insert(item) {
87+
this.root = this.insertUtil(this.root, item);
88+
}
89+
insertUtil(node, item) {
90+
if (node == null) {
91+
// find place to insert
92+
this.nodeCount++;
93+
this.tot++;
94+
return new AVLNode(item);
95+
} else if (this.cmp(item, node) < 0) {
96+
node.left = this.insertUtil(node.left, item);
97+
} else if (this.cmp(item, node) > 0) {
98+
node.right = this.insertUtil(node.right, item);
99+
} else {
100+
node.cnt++;
101+
this.tot++;
102+
return node;
103+
}
104+
this.update(node);
105+
return this.rebalanceAfterInsert(node, item);
106+
}
107+
remove(v) {
108+
this.root = this.removeUtil(this.root, v);
109+
}
110+
removeUtil(node, item) {
111+
if (node == null) {
112+
return node;
113+
} else if (this.cmp(item, node) < 0) {
114+
node.left = this.removeUtil(node.left, item);
115+
} else if (this.cmp(item, node) > 0) {
116+
node.right = this.removeUtil(node.right, item);
117+
} else {
118+
// find node
119+
if (node.cnt > 1) {
120+
// current node > 1, remove 1, tree size keep the same
121+
node.cnt--;
122+
this.tot--;
123+
return node;
124+
} else {
125+
// current node == 1, delete, tree size--
126+
this.nodeCount--;
127+
this.tot--;
128+
}
129+
// delete process
130+
if (node.left == null) {
131+
let tmp = node.right;
132+
node = null;
133+
return tmp;
134+
} else if (node.right == null) {
135+
let tmp = node.left;
136+
node = null;
137+
return tmp;
138+
}
139+
let tmp = this.findMin(node.right);
140+
node.val = tmp.val;
141+
node.right = this.removeUtil(node.right, tmp.val);
142+
}
143+
if (node == null) return node;
144+
this.update(node);
145+
return this.rebalanceAfterDeletion(node, item);
146+
}
147+
rebalanceAfterInsert(node, item) {
148+
let bal = this.getBalance(node);
149+
if (bal > 1 && this.cmp(item, node.left) < 0) return this.RR(node);
150+
if (bal < -1 && this.cmp(item, node.right) > 0) return this.LR(node);
151+
if (bal > 1 && this.cmp(item, node.left) > 0) {
152+
node.left = this.LR(node.left);
153+
return this.RR(node);
154+
}
155+
if (bal < -1 && this.cmp(item, node.right) < 0) {
156+
node.right = this.RR(node.right);
157+
return this.LR(node);
158+
}
159+
return node;
160+
}
161+
rebalanceAfterDeletion(node) {
162+
let bal = this.getBalance(node);
163+
if (bal > 1 && this.getBalance(node.left) >= 0) return this.RR(node);
164+
if (bal < -1 && this.getBalance(node.right) <= 0) return this.LR(node);
165+
if (bal > 1 && this.getBalance(node.left) < 0) {
166+
node.left = this.LR(node.left);
167+
return this.RR(node);
168+
}
169+
if (bal < -1 && this.getBalance(node.right) > 0) {
170+
node.right = this.RR(node.right);
171+
return this.LR(node);
172+
}
173+
return node;
174+
}
175+
find(item) {
176+
return this.findFirstOf(item);
177+
}
178+
findFirstOf(item) {
179+
let node = this.root,
180+
res = null;
181+
while (node != null) {
182+
if (this.cmp(item, node) < 0) {
183+
node = node.left;
184+
} else if (this.cmp(item, node) > 0) {
185+
node = node.right;
186+
} else {
187+
res = node;
188+
node = node.left;
189+
}
190+
}
191+
return res;
192+
}
193+
higher(item) {
194+
// > upper_bound
195+
let node = this.findSuccessorOf(item);
196+
return node == null ? null : node.val;
197+
}
198+
findSuccessorOf(item) {
199+
let node = this.root,
200+
res = null;
201+
while (node != null) {
202+
if (this.cmp(item, node) < 0) {
203+
res = node;
204+
node = node.left;
205+
} else {
206+
node = node.right;
207+
}
208+
}
209+
return res;
210+
}
211+
lower(item) {
212+
// <
213+
let node = this.findPrecursorOf(item);
214+
return node == null ? null : node.val;
215+
}
216+
findPrecursorOf(item) {
217+
let node = this.root,
218+
res = null;
219+
while (node != null) {
220+
if (this.cmp(item, node) > 0) {
221+
res = node;
222+
node = node.right;
223+
} else {
224+
node = node.left;
225+
}
226+
}
227+
return res;
228+
}
229+
findKth(k) {
230+
// (1-indexed) unique
231+
let res = this.findKthNode(k);
232+
return res == null ? null : res.val;
233+
}
234+
findKthNode(k) {
235+
return this.size() < k ? null : this.KthUtil(this.root, k);
236+
}
237+
KthUtil(node, k) {
238+
let leftCount = node.left ? node.left.SubTreeNodes : 0;
239+
if (leftCount + 1 === k) return node;
240+
if (leftCount + 1 < k) return this.KthUtil(node.right, k - leftCount - 1);
241+
return this.KthUtil(node.left, k);
242+
}
243+
rankOf(item) {
244+
// unique value treeset total elements in tree with val < item
245+
let x = this.findPrecursorOf(item);
246+
return x == null ? 0 : this.findRankOf(x, this.root) + 1;
247+
}
248+
findRankOf(item, node) {
249+
let rank = 0;
250+
while (node != null) {
251+
let leftSubtreeNodes = node.left != null ? node.left.SubTreeNodes : 0;
252+
if (this.cmp(item, node) < 0) {
253+
node = node.left;
254+
} else if (this.cmp(item, node) > 0) {
255+
rank += leftSubtreeNodes + 1;
256+
node = node.right;
257+
} else {
258+
return rank + leftSubtreeNodes;
259+
}
260+
}
261+
return 0;
262+
}
263+
has(item) {
264+
return this.count(item) > 0;
265+
}
266+
count(item) {
267+
let node = this.find(item);
268+
return node == null ? 0 : node.cnt;
269+
}
270+
maxx() {
271+
let node = this.findMax(this.root);
272+
return node == null ? null : node.val;
273+
}
274+
minx() {
275+
let node = this.findMin(this.root);
276+
return node == null ? null : node.val;
277+
}
278+
findMin(node) {
279+
return node == null || node.left == null ? node : this.findMin(node.left);
280+
}
281+
findMax(node) {
282+
return node == null || node.right == null ? node : this.findMax(node.right);
283+
}
284+
size() {
285+
return this.nodeCount;
286+
}
287+
total() {
288+
return this.tot;
289+
}
290+
isEmpty() {
291+
return this.root == null;
292+
}
293+
show() {
294+
// inorder
295+
let res = [];
296+
const dfs = (x) => {
297+
if (x == null) return;
298+
dfs(x.left);
299+
res.push(x.val);
300+
dfs(x.right);
301+
};
302+
dfs(this.root);
303+
return res;
304+
}
305+
showAll() {
306+
let d = this.show(),
307+
res = [];
308+
for (const x of d) {
309+
for (let i = 0; i < this.count(x); i++) res.push(x);
310+
}
311+
return res;
312+
}
313+
}
314+
315+
function SORTracker() {
316+
let tree = new AVLTree(),
317+
i = 1;
318+
return { add, get };
319+
function add(name, score) {
320+
tree.insert([name, score]);
321+
}
322+
function get() {
323+
let node = tree.findKthNode(i++);
324+
return node.val[0];
325+
}
326+
}
327+
328+
/**
329+
* Your SORTracker object will be instantiated and called as such:
330+
* var obj = new SORTracker()
331+
* obj.add(name,score)
332+
* var param_2 = obj.get()
333+
*/

0 commit comments

Comments
 (0)