当前位置: 首页 > news >正文

Kimi LeetCode 3569. 分割数组后不同质数的最大数目 Java实现

以下是 LeetCode 3569 分割数组后不同质数的最大数目 的 Java 实现。

核心思路

问题转化

对于每个查询,我们需要找到最优分割点 k,使得:
\text{prefix中不同质数个数} + \text{suffix中不同质数个数}

关键观察:设整个数组中共有 T 个不同的质数。若某个质数 p 的首次出现位置为 l、末次出现位置为 r,则:
- 若分割点 k \in [l+1, r],则 p 在前后两段都出现,贡献为 2(额外收益 +1)
- 否则 p 只出现在一段中,贡献为 1

因此:
\text{答案} = T + \max{k} \{\text{在位置 } k \text{ 处被"两边都有"的质数个数}\}

数据结构

- 埃氏筛:O(10^5) 预处理质数表,O(1) 判断质数
- `TreeSet`(红黑树):对每个质数维护其出现的所有下标,支持 O(\log n) 的插入、删除、查最值
- 懒标记线段树:维护每个分割位置的"额外收益"(即有多少质数在该位置被两边都包含),支持 O(\log n) 的区间加减和区间最大值查询

每次查询修改一个元素时,只需更新受影响质数的区间贡献,然后查询线段树最大值即可。

时间复杂度 O((n+q) \cdot \log n),空间复杂度 O(n)。

```java
import java.util.*;

class Solution {
static final int MX = 100000;
static boolean[] isPrime = new boolean[MX + 1];
static boolean sieveInitialized = false;

// 懒标记线段树:区间加 + 区间最大值
static class SegTree {
int n, size;
int[] mx, lazy;

SegTree(int n) {
this.n = n;
this.size = 1;
while (size < n) size <<= 1;
mx = new int[size << 1];
lazy = new int[size << 1];
}

void apply(int o, int v) {
mx[o] += v;
lazy[o] += v;
}

void push(int o) {
if (lazy[o] != 0) {
apply(o << 1, lazy[o]);
apply(o << 1 | 1, lazy[o]);
lazy[o] = 0;
}
}

void update(int l, int r, int v) {
if (l > r) return;
update(1, 0, size - 1, l, r, v);
}

void update(int o, int L, int R, int l, int r, int v) {
if (l <= L && R <= r) {
apply(o, v);
return;
}
push(o);
int mid = (L + R) >> 1;
if (l <= mid) update(o << 1, L, mid, l, r, v);
if (r > mid) update(o << 1 | 1, mid + 1, R, l, r, v);
mx[o] = Math.max(mx[o << 1], mx[o << 1 | 1]);
}

int queryMax() {
return mx[1];
}
}

public int[] maximumCount(int[] nums, int[][] queries) {
// 埃氏筛预处理质数表(只执行一次)
if (!sieveInitialized) {
Arrays.fill(isPrime, true);
isPrime[0] = isPrime[1] = false;
for (int i = 2; i * i <= MX; i++) {
if (isPrime[i]) {
for (int j = i * i; j <= MX; j += i) {
isPrime[j] = false;
}
}
}
sieveInitialized = true;
}

int n = nums.length;
int q = queries.length;
int[] ans = new int[q];

// pos.get(p) = 质数 p 出现的所有下标(有序)
Map<Integer, TreeSet<Integer>> pos = new HashMap<>();

for (int i = 0; i < n; i++) {
int x = nums[i];
if (isPrime[x]) {
pos.computeIfAbsent(x, k -> new TreeSet<>()).add(i);
}
}

// 线段树:维护每个分割位置的"额外收益"
SegTree seg = new SegTree(n);

// 初始化:出现 ≥2 次的质数,其 [first, last] 区间贡献 +1
for (TreeSet<Integer> indices : pos.values()) {
if (indices.size() >= 2) {
seg.update(indices.first(), indices.last(), 1);
}
}

// 处理每个查询
for (int qi = 0; qi < q; qi++) {
int idx = queries[qi][0];
int val = queries[qi][1];
int old = nums[idx];
nums[idx] = val;

// 删除旧值
if (isPrime[old]) {
TreeSet<Integer> indices = pos.get(old);
if (indices.size() >= 2) {
seg.update(indices.first(), indices.last(), -1);
}
indices.remove(idx);
if (indices.isEmpty()) {
pos.remove(old);
} else if (indices.size() >= 2) {
seg.update(indices.first(), indices.last(), 1);
}
}

// 插入新值
if (isPrime[val]) {
TreeSet<Integer> indices = pos.get(val);
if (indices == null) {
indices = new TreeSet<>();
pos.put(val, indices);
} else {
if (indices.size() >= 2) {
seg.update(indices.first(), indices.last(), -1);
}
}
indices.add(idx);
if (indices.size() >= 2) {
seg.update(indices.first(), indices.last(), 1);
}
}

// 答案 = 总不同质数个数 + 最大额外收益
ans[qi] = pos.size() + seg.queryMax();
}

return ans;
}
}
```

验证示例

输入 输出 说明
`nums = [2,1,3,1,2]`, `queries = [[1,2],[3,3]]` `[3, 4]` 第一次查询后分割得 1+2=3;第二次得 2+2=4
`nums = [2,1,4]`, `queries = [[0,1]]` `[0]` 修改后数组无质数,答案为 0

http://www.jsqmd.com/news/1192633/

相关文章:

  • 【Python实战】从零到一:手把手解决pip安装与典型报错
  • Godogen工作原理解密:AI如何将文本描述转化为完整游戏项目
  • leven:极速字符串差异计算!揭秘最快JS版Levenshtein距离算法
  • 2026年五大管理驾驶舱系统:可视化与实时性解析 - 科技焦点
  • DS250DF210重定时器实战:25Gbps高速链路信号完整性与设计指南
  • 基于Simulink的CDMA多用户扩频仿真:抗噪性能与滤波器参数优化
  • 解锁多语言观影新体验:PotPlayer百度翻译插件完全指南
  • STM32驱动思岚A1M8激光雷达:从串口数据解析到DMA高效处理
  • 舞蹈教育培训教师证书报考资料与全年报名时间说明 - 最新教育培训热点
  • 数字图像处理课程设计-基于PERCLOS的疲劳驾驶预警系统
  • GLM-5.2-colibri-int4模型转换指南:从FP8到INT4的完整流程
  • CANN/asc-devkit:Ascend C SIMD API 算术计算函数
  • 盘活闲置资产!2026无锡黄金回收行业现状与靠谱门店推荐 - 奢品小当家
  • Mamba-UNet训练技巧:超参数调优与损失函数选择最佳实践
  • Spring Security 过滤器链深度解析——认证与授权的幕后英雄
  • STM32最小系统电路设计全解析:从电源到时钟的硬件内功
  • Windows Python开发必备:解决Microsoft Visual C++ 14.0编译环境问题
  • Laravel Developer Roadmap:5步快速入门PHP与Laravel开发终极指南
  • LMZ20501纳米模块电源设计:从原理到PCB布局的完整实战指南
  • Mythos大模型安全能力跃迁:从漏洞发现到端到端攻击模拟
  • Windows开发者必看:dirs-rs如何优雅处理Known Folder API的10个实用技巧
  • SingGuard-8b-GGUF性能深度测评:六大安全基准测试中超越竞品的关键原因
  • 基于74LS系列芯片的拔河游戏机数字逻辑设计与Multisim仿真实现
  • 5个步骤快速上手LittleD:Arduino传感器数据管理实战
  • Trae AI IDE:重构全栈开发工作流的上下文驱动实践
  • 闲置旧金别吃灰!许昌这6家宝藏黄金回收店,上门秒打款,全区县都能约! - 清奢黄金上门回收
  • RF430CL331H NFC标签芯片非阻塞写入与中断处理机制详解
  • 基于51单片机的多模式洗衣机控制系统设计与Proteus仿真
  • 3个核心技巧:用cg-use-everywhere彻底改变你的ComfyUI工作流
  • NCMconverter:5分钟掌握专业NCM音频格式转换工具