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

DeepSeek LeetCode 2911. 得到 K 个半回文串的最少修改次数 TypeScript实现

以下是 LeetCode 2911 题「得到 K 个半回文串的最少修改次数」的 TypeScript 实现,包含完整的类型定义和详细的注释。

```typescript
/**
* 计算将字符串 s 分成 k 个半回文子串所需的最少修改次数
* @param s 原始字符串
* @param k 需要分成的子串数目
* @returns 最少修改次数
*/
function minimumChanges(s: string, k: number): number {
const n: number = s.length;

// ---------- 1. 预处理 cost[l][r]:子串 s[l..r] 变成半回文的最小修改次数 ----------
const cost: number[][] = Array.from({ length: n }, () => Array(n).fill(Infinity));

// 枚举所有子串
for (let l = 0; l < n; l++) {
for (let r = l; r < n; r++) {
const len: number = r - l + 1;
if (len < 2) continue; // 长度至少为 2 才能成为半回文

let best: number = Infinity;
// 枚举 len 的所有真因子 d (1 <= d < len 且 len % d === 0)
for (let d = 1; d < len; d++) {
if (len % d !== 0) continue;

let changes: number = 0;
// 遍历 d 个轨道,每个轨道的起点偏移 start = 0 .. d-1
for (let start = 0; start < d; start++) {
// 该轨道的字符下标:l+start, l+start+d, l+start+2d, ...
// 双指针从两端向中间比较
let i: number = l + start;
let j: number = l + start + Math.floor((len - 1 - start) / d) * d;
while (i < j) {
if (s[i] !== s[j]) changes++;
i += d;
j -= d;
}
}
best = Math.min(best, changes);
}
cost[l][r] = best;
}
}

// ---------- 2. 动态规划:将前 i 个字符分成 c 段的最小代价 ----------
// dp[i][c] 表示 s[0..i-1] 分成 c 段的最小修改次数
const dp: number[][] = Array.from({ length: n + 1 }, () => Array(k + 1).fill(Infinity));
dp[0][0] = 0; // 空串分成 0 段代价为 0

for (let c = 1; c <= k; c++) {
for (let i = c; i <= n; i++) {
// 枚举最后一段的起始位置 j(前 j 个字符已经分成 c-1 段)
for (let j = c - 1; j < i; j++) {
if (dp[j][c - 1] !== Infinity && cost[j][i - 1] !== Infinity) {
dp[i][c] = Math.min(dp[i][c], dp[j][c - 1] + cost[j][i - 1]);
}
}
}
}

return dp[n][k];
}
```

核心思路说明

1. 半回文串的判断与最小修改

· 定义:长度为 L 的字符串,若存在一个真因子 d(1 ≤ d < L 且 L % d == 0),使得将所有下标按模 d 分组后,每组都是回文串,则称为半回文。
· 最小修改计算:
· 对于每个可行的 d,将原串划分为 d 条轨道(每条轨道由间隔 d 的下标组成)。
· 对每条轨道使用双指针从两端向中间比较,统计不相等的字符对数。
· 所有轨道的对数之和即为按该 d 划分需要的修改次数。
· 取所有 d 中的最小值作为该子串的半回文最小修改代价。

2. 预处理 cost 数组

· 枚举所有子串 s[l..r],计算其最小修改次数,结果存入 cost[l][r]。
· 复杂度 O(n³),在 n ≤ 200 时可接受(约 800 万次操作)。

3. 动态规划划分

· dp[i][c]:前 i 个字符(s[0..i-1])分成 c 段的最小修改次数。
· 转移方程:
dp[i][c] = min( dp[j][c-1] + cost[j][i-1] ),其中 c-1 ≤ j < i。
· 初始状态:dp[0][0] = 0,其余为无穷大。
· 最终答案:dp[n][k]。

4. 边界与优化

· 若 k > n,理论上无法分割(题目保证不会出现此类情况)。
· 长度小于 2 的子串无法成为半回文,cost 保留 Infinity,DP 时会自动跳过非法划分。

复杂度分析

· 时间:预处理 O(n³),DP O(n²·k)。
· 空间:O(n² + n·k),其中 cost 数组占 O(n²),dp 表占 O(n·k)。

测试示例

```typescript
// 示例 1
console.log(minimumChanges("abcde", 2)); // 输出: 2

// 示例 2
console.log(minimumChanges("aabbaa", 3)); // 输出: 0
```

如需进一步解释半回文定义或优化细节,欢迎继续提问!

http://www.rkmt.cn/news/1445413.html

相关文章:

  • 【Agent】OpenCode 接入 DeepSeek-V4-Pro 开启1M上下文 保姆级教程
  • 【智能制造】- APS系列|16 生产计划与生产排程:核心概念与分类
  • 微软音频技术三十年:从语音降噪到空间音频的演进与应用
  • 公司日常考勤系统毕业设计
  • 索尼发布带 ‘True RGB‘ 背光的 Bravia 9 II 和 Bravia 7 II,色彩表现更出色!
  • 别再只用plt.plot了!Matplotlib面向对象接口实战:从脚本到Notebook的完整配置指南
  • 在Visual Studio中集成Python、Jupyter与.NET,打造高效研究工作站
  • 【Sora 2教育视频制作黄金法则】:20年AI教育专家亲授5大不可绕过的生成逻辑与避坑指南
  • C++类和对象(上):一文搞懂基础定义与核心规则
  • 聚力绿色包装创新,interpack China×WPO 上海盛会 11 月启幕
  • 电网设备拓扑图一键自动排布工具(基于FR力导向算法)
  • 职场人必备!高颜值电脑音乐播放器YesPlayMusicV0.4.10
  • Oura Ring 5 发布:体积缩小40%,新增血压追踪与睡眠呼吸分析
  • 2026年天津建设工程律师避坑指南:5位建工经验丰富靠谱推荐 - 本地品牌推荐
  • 定理证明器在干细胞生物学中的应用:形式化建模与逻辑推理
  • 从零到一:用Python和SQLAlchemy玩转MIMIC-IV数据库(实战数据分析流程)
  • 大模型自动化领域自适应:从通用到专业的低成本迁移方案
  • 500+免费插件:让RPG Maker MV/MZ实现专业级游戏开发的终极指南
  • 体育直播AI化倒计时!Sora 2已通过FIFA技术认证,但92%团队正误用“运动连贯性参数”——即刻修正的4个致命配置
  • 从随机到精确:现代采样方法的核心演进与工程实践
  • FastSpeech:非自回归语音合成的速度、准确性与可控性革命
  • Ubuntu 20.04/22.04下,Isaac Gym的Segmentation fault坑我踩完了,这是最全的避坑指南
  • KMS智能激活实战宝典:从零掌握Windows与Office永久激活秘籍
  • 别再死记硬背了!用Simulink手把手复现双三相电机VSD建模(附模型文件)
  • 告别黑白终端!用Python的termcolor库给你的日志和CLI工具加点‘颜色’
  • AI生成代码的合规、版权与漏洞治理(传统IT转型专项课题)
  • Diablo Edit2完全指南:暗黑破坏神2角色编辑器终极使用教程
  • UE5蓝图实战:用样条线+Spline组件打造可交互的3D测距工具(附完整项目文件)
  • 量身定做网络工程师日常运维的MCP Server企业级工具
  • 后量子密码学FrodoKEM:基于LWE的保守安全方案解析