|
| 1 | +/** |
| 2 | + * @param {number[][]} buildings |
| 3 | + * @return {number[][]} |
| 4 | + */ |
| 5 | +const getSkyline = function (b) { |
| 6 | + const a = []; const h = new RemovableHeap((a, b) => b - a) |
| 7 | + for (const [l, r, h] of b) { |
| 8 | + a.push([l, h, 1]) |
| 9 | + a.push([r, h, -1]) |
| 10 | + } |
| 11 | + a.sort((x, y) => x[0] - y[0]) |
| 12 | + const ans = [] |
| 13 | + for (let i = 0; i < a.length;) { |
| 14 | + const x = a[i][0]; let j = i |
| 15 | + while (j < a.length && a[j][0] === x) { |
| 16 | + const [_, y, f] = a[j] |
| 17 | + if (f === -1) h.remove(y) |
| 18 | + else h.push(y) |
| 19 | + j++ |
| 20 | + } |
| 21 | + i = j |
| 22 | + const cur = h.top() ?? 0 |
| 23 | + if (!ans.length || ans[ans.length - 1][1] !== cur) { |
| 24 | + ans.push([x, cur]) |
| 25 | + } |
| 26 | + } |
| 27 | + return ans |
| 28 | +} |
| 29 | + |
| 30 | +class Heap { |
| 31 | + constructor (data = [], compare = (lhs, rhs) => lhs < rhs ? -1 : lhs > rhs ? 1 : 0) { |
| 32 | + if (typeof data === 'function') { |
| 33 | + compare = data |
| 34 | + data = [] |
| 35 | + } |
| 36 | + this.data = [null, ...data] |
| 37 | + this.lt = (i, j) => compare(this.data[i], this.data[j]) < 0 |
| 38 | + for (let i = this.size(); i > 0; i--) { this.heapify(i) } |
| 39 | + } |
| 40 | + |
| 41 | + size () { |
| 42 | + return this.data.length - 1 |
| 43 | + } |
| 44 | + |
| 45 | + push (v) { |
| 46 | + this.data.push(v) |
| 47 | + let i = this.size() |
| 48 | + while (i >> 1 !== 0 && this.lt(i, i >> 1)) { this.swap(i, i >>= 1) } |
| 49 | + } |
| 50 | + |
| 51 | + pop () { |
| 52 | + this.swap(1, this.size()) |
| 53 | + const top = this.data.pop() |
| 54 | + this.heapify(1) |
| 55 | + return top |
| 56 | + } |
| 57 | + |
| 58 | + top () { |
| 59 | + return this.data[1] |
| 60 | + } |
| 61 | + |
| 62 | + heapify (i) { |
| 63 | + while (true) { |
| 64 | + let min = i |
| 65 | + const [l, r, n] = [i * 2, i * 2 + 1, this.data.length] |
| 66 | + if (l < n && this.lt(l, min)) { min = l } |
| 67 | + if (r < n && this.lt(r, min)) { min = r } |
| 68 | + if (min !== i) { |
| 69 | + this.swap(i, min) |
| 70 | + i = min |
| 71 | + } else { break } |
| 72 | + } |
| 73 | + } |
| 74 | + |
| 75 | + clear () { |
| 76 | + this.data = [null] |
| 77 | + } |
| 78 | + |
| 79 | + swap (i, j) { |
| 80 | + const d = this.data; |
| 81 | + [d[i], d[j]] = [d[j], d[i]] |
| 82 | + } |
| 83 | +} |
| 84 | + |
| 85 | +class RemovableHeap { |
| 86 | + constructor (data = [], cmp) { |
| 87 | + this.heap = new Heap(data, cmp) |
| 88 | + this.counts = new Map() |
| 89 | + this._invalidCount = 0 |
| 90 | + for (let i = 1; i < this.heap.data.length; i++) { |
| 91 | + this._setCount(this.heap.data[i], 1) |
| 92 | + } |
| 93 | + } |
| 94 | + |
| 95 | + size () { |
| 96 | + return this.heap.size() - this._invalidCount |
| 97 | + } |
| 98 | + |
| 99 | + top () { |
| 100 | + this._normalize() |
| 101 | + return this.heap.top() |
| 102 | + } |
| 103 | + |
| 104 | + pop () { |
| 105 | + this._normalize() |
| 106 | + if (this.heap.size() < 1) { return void 0 } |
| 107 | + const top = this.heap.pop() |
| 108 | + this._setCount(top, -1) |
| 109 | + return top |
| 110 | + } |
| 111 | + |
| 112 | + push (num) { |
| 113 | + this._setCount(num, 1) |
| 114 | + this.heap.push(num) |
| 115 | + } |
| 116 | + |
| 117 | + remove (num) { |
| 118 | + if (Number(this.counts.get(num)) > 0) { |
| 119 | + this._setCount(num, -1) |
| 120 | + this._invalidCount++ |
| 121 | + } |
| 122 | + } |
| 123 | + |
| 124 | + has (value) { |
| 125 | + return this.counts.get(value) > 0 |
| 126 | + } |
| 127 | + |
| 128 | + _setCount (num, diff) { |
| 129 | + let _a |
| 130 | + const count = (_a = this.counts.get(num)) != null ? _a : 0 |
| 131 | + this.counts.set(num, count + diff) |
| 132 | + } |
| 133 | + |
| 134 | + _normalize () { |
| 135 | + while (this.heap.size() && !this.counts.get(this.heap.top())) { |
| 136 | + this.heap.pop() |
| 137 | + this._invalidCount-- |
| 138 | + } |
| 139 | + } |
| 140 | +} |
0 commit comments