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

Kimi k2.6 LeetCode 3003. 执行操作后的最大分割数量 Java实现

以下是 LeetCode 3003. 执行操作后的最大分割数量 的 Java 实现。这道题有两种主流解法:

1. 状态压缩 + 记忆化搜索(代码简洁,但复杂度分析需要仔细理解)
2. 前后缀分解(线性复杂度,实现较复杂)

这里提供两种实现:

---

解法一:状态压缩 + 记忆化搜索(推荐)

核心思路:用 `mask`(位掩码)记录当前分割块中已出现的字符集合,`cur` 表示当前块中不同字符的数量。`t` 标记是否还能修改一个字符。

```java
class Solution {
private Map<List<Integer>, Integer> f = new HashMap<>();
private String s;
private int k;
private int n;

public int maxPartitionsAfterOperations(String s, int k) {
this.s = s;
this.k = k;
this.n = s.length();
return dfs(0, 0, 1);
}

/**
* 记忆化搜索
* @param i 当前处理到的位置
* @param cur 当前分割块的字符掩码(位掩码)
* @param t 是否还能修改一个字符(1=可以,0=已用掉)
* @return 从位置 i 开始能获得的最大分割数
*/
private int dfs(int i, int cur, int t) {
if (i >= n) {
return 1; // 到达末尾,最后一个分割块计数
}

var key = List.of(i, cur, t);
if (f.containsKey(key)) {
return f.get(key);
}

// 当前字符的位掩码
int v = 1 << (s.charAt(i) - 'a');
int nxt = cur | v;
int ans;

// 不修改当前字符
if (Integer.bitCount(nxt) > k) {
// 当前字符加入后超过 k 个不同字符,必须开启新分割块
ans = dfs(i + 1, v, t) + 1;
} else {
// 继续当前分割块
ans = dfs(i + 1, nxt, t);
}

// 尝试修改当前字符(如果还能修改)
if (t > 0) {
for (int j = 0; j < 26; j++) {
nxt = cur | (1 << j);
if (Integer.bitCount(nxt) > k) {
// 修改后需要开启新分割块
ans = Math.max(ans, dfs(i + 1, 1 << j, 0) + 1);
} else {
// 修改后继续当前分割块
ans = Math.max(ans, dfs(i + 1, nxt, 0));
}
}
}

f.put(key, ans);
return ans;
}
}
```

---

解法二:前后缀分解(线性复杂度)

核心思路:修改位置 `i` 的字符只会影响包含 `s[i]` 的那个分割块。预处理左右两侧的分割信息,枚举每个修改位置快速计算。

```java
class Solution {
public int maxPartitionsAfterOperations(String s, int k) {
int n = s.length();

// left[i][0] = s[0..i-1] 的完整分割数
// left[i][1] = s[0..i-1] 最后一个未满块的字符掩码
// left[i][2] = s[0..i-1] 最后一个未满块的不同字符数
int[][] left = new int[n + 1][3];
// right[i][0] = s[i..n-1] 的完整分割数
// right[i][1] = s[i..n-1] 第一个未满块的字符掩码
// right[i][2] = s[i..n-1] 第一个未满块的不同字符数
int[][] right = new int[n + 1][3];

// 预处理左侧
int num = 0, mask = 0, count = 0;
for (int i = 0; i < n; i++) {
int bit = 1 << (s.charAt(i) - 'a');
if ((mask & bit) == 0) { // 新字符
count++;
if (count <= k) {
mask |= bit;
} else {
// 开启新块
num++;
mask = bit;
count = 1;
}
}
left[i + 1][0] = num;
left[i + 1][1] = mask;
left[i + 1][2] = count;
}

// 预处理右侧(反向)
num = 0;
mask = 0;
count = 0;
for (int i = n - 1; i >= 0; i--) {
int bit = 1 << (s.charAt(i) - 'a');
if ((mask & bit) == 0) {
count++;
if (count <= k) {
mask |= bit;
} else {
num++;
mask = bit;
count = 1;
}
}
right[i][0] = num;
right[i][1] = mask;
right[i][2] = count;
}

int maxPartitions = left[n][0] + 1; // 不修改的情况

// 枚举修改位置 i
for (int i = 0; i < n; i++) {
// 默认:左侧完整分割 + 右侧完整分割 + 中间 2 块(修改点单独成块或合并)
int seg = left[i][0] + right[i + 1][0] + 2;

int leftMask = left[i][1];
int rightMask = right[i + 1][1];
int totalMask = leftMask | rightMask;
int totalCount = Integer.bitCount(totalMask);

// 情况1:左右未满块 + 修改后的字符可以合并为 1 块
// 需要 totalCount + 1 <= k(+1 是给修改后的字符留的位置)
if (Math.min(totalCount + 1, 26) <= k) {
seg--; // 合并为 1 块,总分割数减 1
}
// 情况2:左右块都已满(各 k 个字符),且存在一个两者都没出现的字符
// 修改后的字符可以独立成块,使中间区域分裂为 3 块
else if (left[i][2] == k && right[i + 1][2] == k && totalCount < 26) {
seg++; // 分裂为 3 块,总分割数加 1
}

maxPartitions = Math.max(maxPartitions, seg);
}

return maxPartitions;
}
}
```

---

两种解法对比

特性 状态压缩 + 记忆化搜索 前后缀分解
时间复杂度 O(n \times 2^{26}) 表面,实际有效状态 O(n \times 26 \times 26) O(n)
空间复杂度 O(n \times 2^{26}) 表面,实际有效状态有限 O(n)
代码复杂度 简洁,约 40 行 较复杂,约 80 行
核心思想 直接模拟分割过程,枚举修改 利用"修改只影响局部"的性质

关键点说明

- 位掩码 `mask`:用一个 int 的 26 个二进制位表示 a-z 字符是否在当前分割块中出现
- `Integer.bitCount()`:计算掩码中 1 的个数,即不同字符数量
- 记忆化状态:`(i, cur, t)` 表示从位置 `i` 开始,当前块字符掩码为 `cur`,是否还能修改的状态。虽然 `cur` 有 2^{26} 种可能,但实际遍历中有效状态远少于这个数

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

相关文章:

  • AntiDupl.NET图片去重终极指南:快速清理重复图片的完整教程
  • 效率提升:用快马AI自动化工具快速处理付款未获批准事项
  • 3步开启你的浏览器PPT创作革命:PPTist在线演示文稿完全指南
  • 如何3分钟告别手动刷课:智慧职教自动化学习助手完整指南
  • COM3D2终极实时编辑器:5分钟掌握游戏角色属性修改技巧
  • Kimi k2.6 LeetCode 3003. 执行操作后的最大分割数量 Go实现
  • 别再死记硬背!一个‘顾客到达’的例子,彻底搞懂复合泊松过程的期望与方差推导
  • 告别重复造轮子:用快马一键生成gptimage2安卓版高效开发模板
  • 实战指南:基于快马ai快速开发can总线监控与诊断上位机软件
  • 五步构建完美黑苹果系统:OpenCore引导配置完全指南
  • DankDroneDownloader:无人机固件自由与历史版本恢复的终极解决方案
  • AI注销不是删除,而是智能遗忘:解析联邦学习+差分隐私双引擎注销架构(附开源POC代码)
  • 三分钟破解Axure语言障碍:中文界面本地化实战方案
  • 融资超500亿!DeepSeek估值逼近600亿美元,腾讯宁德时代争相入局
  • [特殊字符] 拼多多大厂笔试题——正则表达式
  • 2026年中央空调清洗公司推荐哪些?商业楼宇空调系统清洗选型指南 - 华旭传媒
  • 实战应用:基于快马平台开发带历史记录与偏好设置的夺命许愿软件
  • 如何快速掌握免费音乐歌词获取工具:面向音乐爱好者的完整使用指南
  • SWAT模型实战踩坑记:.sol文件为空、气象数据缺失?手把手教你诊断与修复
  • Kimi k2.6 LeetCode 2972. 统计移除递增子数组的数目 II Python3实现
  • SourceGit:让Git版本控制变得直观高效的跨平台图形化解决方案
  • 智慧教育平台电子课本一键解析:告别繁琐下载的智能解决方案
  • 新手福音:用快马平台生成练习项目,轻松理解github协作开发
  • 【会议征稿通知 | 中国教育发展战略学会教育大数据专业委员会主办 | SPIE出版 | EI 、Scopus稳定检索】第六届先进算法与信号、图像处理国际学术会议(AASIP 2026)
  • 别再怕约束了!手把手教你用QUBO模型把复杂优化问题‘拍扁’成无约束问题
  • 【深度解析】Gemma 4 12B:面向本地 Agent 工作流的统一多模态模型与 OpenAI 兼容接入实践
  • ContextMenuForWindows11开源项目:彻底解放你的右键菜单生产力
  • 如何快速构建你的专属离线英语发音库:11万单词MP3音频一键下载指南
  • LabVIEW 2019生成DLL实战:手把手教你用C# WinForm调用(附避坑指南)
  • 如何永久保存微信聊天记录:掌握你的数字记忆主权