题目:原题链接(困难)
标签:二分查找、线段树、设计
解法 | 时间复杂度 | 空间复杂度 | 执行用时 |
Ans 1 (Python) | 624ms (50.00%) | ||
Ans 2 (Python) | |||
Ans 3 (Python) |
解法一:
import bisect
import collections
from typing import List
class MajorityChecker:
def __init__(self, arr: List[int]):
self.high = len(arr).bit_length()
self.size = 2 ** self.high - 1
# 构造线段树
self.tree = [(0, 0)] * (2 * self.size + 1)
# 计算叶结点
for i in range(len(arr)):
self.tree[self.size + i] = (arr[i], 1)
# 计算中间节点
for i in range(self.high - 1, -1, -1):
for j in range(2 ** i - 1, 2 ** (i + 1) - 1):
left_val, left_count = self.tree[j * 2 + 1]
right_val, right_count = self.tree[j * 2 + 2]
self.tree[j] = self.merge(left_val, left_count, right_val, right_count)
# 统计每一个的数的坐标列表
self.idx = collections.defaultdict(list)
for i, num in enumerate(arr):
self.idx[num].append(i)
def query(self, left: int, right: int, threshold: int) -> int:
# ---------- 摩尔投票法寻找需要查询的数字 ----------
l = left + self.size
r = right + self.size
val, count = 0, 0
# print(left, right)
while l <= r:
if not l & 1: # 左侧为右结点
val, count = self.merge(val, count, self.tree[l][0], self.tree[l][1])
# print("添加:", left, self.tree[left])
l //= 2
else:
l //= 2
if r & 1: # 右侧为左节点
val, count = self.merge(val, count, self.tree[r][0], self.tree[r][1])
# print("添加:", right, self.tree[right])
r = r // 2 - 1
else:
r = r // 2 - 1
# print(left, right)
l_idx = bisect.bisect_left(self.idx[val], left)
r_idx = bisect.bisect_right(self.idx[val], right)
# print("最多值:", val, "超过其他的数量:", count, "->", "查询值:", [left, right], self.idx[val], "->", l_idx, r_idx)
if r_idx - l_idx >= threshold:
return val
else:
return -1
@staticmethod
def merge(v1, c1, v2, c2):
if v1 == v2:
return v1, c1 + c2
else:
if c1 < c2:
v1, c1, v2, c2 = v2, c2, v1, c1
return v1, c1 -