-
Notifications
You must be signed in to change notification settings - Fork 31
/
RangeModeQuery.ts
171 lines (157 loc) · 4.57 KB
/
RangeModeQuery.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
/* eslint-disable no-constant-condition */
/**
* 在线查询区间众数(出现次数最多的数以及出现的次数).
*/
class RangeModeQuery {
private static _compress(arr: number[]): [sorted: Uint32Array, compressed: Uint32Array] {
const set = new Set<number>(arr)
const sorted = new Uint32Array(set.size)
let index = 0
set.forEach(v => {
sorted[index++] = v
})
sorted.sort((a, b) => a - b)
const rank = new Map<number, number>()
sorted.forEach((v, i) => {
rank.set(v, i)
})
const compressed = new Uint32Array(arr.length)
for (let i = 0; i < arr.length; i++) {
compressed[i] = rank.get(arr[i])!
}
return [sorted, compressed]
}
private readonly _value: Uint32Array
private readonly _rank: Uint32Array
private readonly _mode: Uint32Array[]
private readonly _freq: Uint32Array[]
private readonly _qs: number[][]
private readonly _t: number
private readonly _sorted: Uint32Array
/**
* O(nsqrt(n))构建.
*/
constructor(arr: number[]) {
const n = arr.length
const [sorted, value] = RangeModeQuery._compress(arr)
const t = Math.max(1, Math.ceil(Math.sqrt(n)))
const rank = new Uint32Array(n)
const qs: number[][] = Array(n)
for (let i = 0; i < n; i++) {
qs[i] = []
}
for (let i = 0; i < n; i++) {
const e = value[i]
rank[i] = qs[e].length
qs[e].push(i)
}
const bc = ~~(n / t) + 1
const mode: Uint32Array[] = Array(bc)
const freq: Uint32Array[] = Array(bc)
for (let i = 0; i < bc; i++) {
mode[i] = new Uint32Array(bc)
freq[i] = new Uint32Array(bc)
}
for (let f = 0; f * t <= n; f++) {
const freq_ = new Uint32Array(n)
let curMode = 0
let curFreq = 0
for (let l = f + 1; l * t <= n; l++) {
for (let i = (l - 1) * t; i < l * t; i++) {
const e = value[i]
freq_[e]++
if (freq_[e] > curFreq) {
curMode = e
curFreq = freq_[e]
}
}
mode[f][l] = curMode
freq[f][l] = curFreq
}
}
this._value = value
this._rank = rank
this._mode = mode
this._freq = freq
this._qs = qs
this._t = t
this._sorted = sorted
}
/**
* O(sqrt(n))查询区间 [start, end) 中出现次数最多的数mode, 以及出现的次数freq.
*/
query(start: number, end: number): [mode: number, freq: number] {
if (start >= end) {
throw new Error(`invalid range: [${start}, ${end})`)
}
if (start < 0) start = 0
if (end > this._value.length) end = this._value.length
const T = this._t
const bf = ~~(start / T) + 1
const bl = ~~(end / T)
if (bf >= bl) {
let resMode = 0
let resFreq = 0
for (let i = start; i < end; i++) {
const rank = this._rank[i]
const value = this._value[i]
const v = this._qs[value]
const lenV = v.length
while (true) {
const idx = rank + resFreq
if (idx >= lenV || v[idx] >= end) {
break
}
resMode = value
resFreq++
}
}
return [this._sorted[resMode], resFreq]
}
let resMode = this._mode[bf][bl]
let resFreq = this._freq[bf][bl]
for (let i = start; i < bf * T; i++) {
const rank = this._rank[i]
const value = this._value[i]
const v = this._qs[value]
const lenV = v.length
while (true) {
const idx = rank + resFreq
if (idx >= lenV || v[idx] >= end) {
break
}
resMode = value
resFreq++
}
}
for (let i = bl * T; i < end; i++) {
const rank = this._rank[i]
const value = this._value[i]
const v = this._qs[value]
const lenV = v.length
while (true) {
const idx = rank - resFreq
if (idx < 0 || idx >= lenV || v[idx] < start) {
break
}
resMode = value
resFreq++
}
}
return [this._sorted[resMode], resFreq]
}
}
if (require.main === module) {
// https://leetcode.cn/problems/online-majority-element-in-subarray/submissions/
class MajorityChecker {
private readonly _rmq: RangeModeQuery
constructor(arr: number[]) {
this._rmq = new RangeModeQuery(arr)
}
query(left: number, right: number, threshold: number): number {
const [mode, freq] = this._rmq.query(left, right + 1)
return freq >= threshold ? mode : -1
}
}
}
export { RangeModeQuery }