0
点赞
收藏
分享

微信扫一扫

LeetCode题解(1157):子数组中占绝大多数的元素(Python)


题目:​​原题链接​​(困难)

标签:二分查找、线段树、设计

解法

时间复杂度

空间复杂度

执行用时

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 -


举报

相关推荐

0 条评论