news 2026/7/29 12:50:05

DeepSeek LeetCode 3762. 使数组元素相等的最小操作次数 Python3实现

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
DeepSeek LeetCode 3762. 使数组元素相等的最小操作次数 Python3实现

这道题是 LeetCode 第 478 场周赛的 Q4,难度为困难。核心解法是判断区间合法性(同余)+ 中位数贪心 + 可持久化线段树查询区间第 k 小。

---

核心思路

1. 可行性判断(同余):每次操作改变量为 k 的倍数,元素 mod k 的值不变。因此区间内所有元素必须模 k 同余,否则返回 -1。预处理差分数组可 O(1) 判断任意区间是否合法。
2. 最小操作次数(中位数贪心):若所有元素可变为相等,让它们都变成区间的中位数时操作次数最少。设区间长度为 m,中位数为 v(第 (m+1)//2 小),前 x 小元素和为 s0,剩余元素和为 s1,则:
ans = (v * x - s0) // k + (s1 - v * (m - x)) // k
3. 数据结构(可持久化线段树/主席树):需快速查询任意区间的第 k 小值及前 k 小元素之和。使用可持久化线段树(主席树),每个版本 root[i] 对应前缀 nums[0..i] 的权值线段树。

---

Python3 代码实现

```python
from typing import List
import bisect

class PersistentSegTree:
"""可持久化线段树(主席树),支持查询区间第k小及前k小和"""

def __init__(self, nums: List[int]):
# 离散化
self.vals = sorted(set(nums))
self.n = len(self.vals)
self.idx = {v: i + 1 for i, v in enumerate(self.vals)} # 1-based

# 动态开点数组
self.left = [0]
self.right = [0]
self.cnt = [0]
self.sum = [0]

# 构建版本树
self.roots = [0]
for num in nums:
self.roots.append(self._update(self.roots[-1], 1, self.n, self.idx[num], num))

def _update(self, prev: int, l: int, r: int, pos: int, val: int) -> int:
"""插入一个新节点,返回新节点下标"""
cur = len(self.cnt)
self.left.append(self.left[prev])
self.right.append(self.right[prev])
self.cnt.append(self.cnt[prev] + 1)
self.sum.append(self.sum[prev] + val)

if l != r:
mid = (l + r) // 2
if pos <= mid:
new_left = self._update(self.left[prev], l, mid, pos, val)
self.left[cur] = new_left
else:
new_right = self._update(self.right[prev], mid + 1, r, pos, val)
self.right[cur] = new_right
return cur

def _query_kth(self, u: int, v: int, l: int, r: int, k: int) -> int:
"""查询区间 [l, r] 的第 k 小值(返回离散化前的值)"""
if l == r:
return self.vals[l - 1]
mid = (l + r) // 2
left_count = self.cnt[self.left[v]] - self.cnt[self.left[u]]
if left_count >= k:
return self._query_kth(self.left[u], self.left[v], l, mid, k)
else:
return self._query_kth(self.right[u], self.right[v], mid + 1, r, k - left_count)

def _query_sum_le(self, u: int, v: int, l: int, r: int, limit: int) -> tuple:
"""查询区间内 <= limit 的元素个数和元素和,limit 为离散化下标"""
if l == r:
return self.cnt[v] - self.cnt[u], self.sum[v] - self.sum[u]
if r <= limit:
return self.cnt[v] - self.cnt[u], self.sum[v] - self.sum[u]
mid = (l + r) // 2
if limit <= mid:
return self._query_sum_le(self.left[u], self.left[v], l, mid, limit)
else:
lc, ls = self._query_sum_le(self.left[u], self.left[v], l, mid, limit)
rc, rs = self._query_sum_le(self.right[u], self.right[v], mid + 1, r, limit)
return lc + rc, ls + rs

def kth(self, l: int, r: int, k: int) -> int:
"""查询原数组区间 [l, r] 的第 k 小值(0-based)"""
return self._query_kth(self.roots[l], self.roots[r + 1], 1, self.n, k)

def sum_le(self, l: int, r: int, limit_val: int) -> tuple:
"""查询原数组区间 [l, r] 内 <= limit_val 的元素个数和元素和(0-based)"""
limit_idx = bisect.bisect_right(self.vals, limit_val)
if limit_idx == 0:
return 0, 0
return self._query_sum_le(self.roots[l], self.roots[r + 1], 1, self.n, limit_idx)


class Solution:
def minOperations(self, nums: List[int], k: int, queries: List[List[int]]) -> List[int]:
n = len(nums)

# 1. 预处理:判断区间内模k是否同余
# diff[i] = 1 表示 nums[i] 和 nums[i-1] 模k不同余
diff = [0] * n
for i in range(1, n):
diff[i] = diff[i - 1] + (0 if (nums[i] - nums[i - 1]) % k == 0 else 1)

# 2. 原数组前缀和
prefix_sum = [0] * (n + 1)
for i, num in enumerate(nums):
prefix_sum[i + 1] = prefix_sum[i] + num

# 3. 构建主席树
pst = PersistentSegTree(nums)

ans = []
for l, r in queries:
if l == r:
ans.append(0)
continue

# 判断区间内是否所有元素模k同余
if diff[r] - diff[l] != 0:
ans.append(-1)
continue

length = r - l + 1
x = (length + 1) // 2 # 中位数位置(第x小)

# 查询中位数的值
median = pst.kth(l, r, x)

# 查询前x小的元素个数和元素和(即 <= median 的部分)
cnt_le, sum_le = pst.sum_le(l, r, median)

# 剩余元素的和
sum_total = prefix_sum[r + 1] - prefix_sum[l]
sum_gt = sum_total - sum_le

# 计算操作次数
ops = (median * cnt_le - sum_le) // k + (sum_gt - median * (length - cnt_le)) // k
ans.append(ops)

return ans
```

---

复杂度分析

· 时间复杂度:预处理 O(n log n),每个查询 O(log n),总体 O((n + q) log n)
· 空间复杂度:O(n log n)

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/7/29 12:49:21

亦唐科技:物联网(IoT)技术引领智能制造新时代

智能制造是全球工业发展的新方向&#xff0c;作为工业革命的第四阶段&#xff0c;智能制造不仅涉及自动化生产过程的数字化、智能化&#xff0c;还包括智能设备的互联互通、数据的高效分析与应用等方面。在这个过程中&#xff0c;物联网&#xff08;IoT&#xff09;技术的应用为…

作者头像 李华
网站建设 2026/7/29 12:49:19

抖音无水印批量下载神器:3分钟学会专业级视频保存方案

抖音无水印批量下载神器&#xff1a;3分钟学会专业级视频保存方案 【免费下载链接】douyin-downloader A practical Douyin downloader for both single-item and profile batch downloads, with progress display, retries, SQLite deduplication, and browser fallback suppo…

作者头像 李华
网站建设 2026/7/29 12:48:43

适配职称评审论文的论文降重效果类工具怎么选

2026年职称评审的学术合规要求持续收紧&#xff0c;重复率检测、AI生成内容筛查的标准都明显升级&#xff0c;一旦论文重复率不达标或者AI检出率超标&#xff0c;直接会被退回修改&#xff0c;甚至直接取消评审资格&#xff0c;影响职称晋升进度。大多数参评人员平时忙于工作&a…

作者头像 李华
网站建设 2026/7/29 12:48:32

上脚直接焊在脚上

谁懂啊&#xff01;刷了几十条李耕耘的日常vlog 终于扒出他穿到磨边的「隐形出镜王」&#x1f45f;✅ 废土做旧小众设计 完全不撞款的暗纹肌理 自带电影感氛围感&#xff0c;随手一拍都是大片 不用堆配饰&#xff0c;整身穿搭直接提一个档次✅ 全衣柜通杀百搭款 亲测配阔腿裤/工…

作者头像 李华