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

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

由于你再次询问同一题,我会提供一份更注重可读性 + 优化细节的 JavaScript 实现,并附上详细的思路注释,帮助你彻底理解半回文串的处理方式。

```javascript
/**
* 2911. 得到 K 个半回文串的最少修改次数
* @param {string} s
* @param {number} k
* @return {number}
*/
var minimumChanges = function(s, k) {
const n = s.length;

// ---------- 1. 预处理所有子串变成半回文的最小修改次数 ----------
// cost[l][r] 表示 s[l..r] (闭区间) 的最小修改次数,如果无法构成半回文则为 Infinity
const cost = Array.from({ length: n }, () => new Array(n).fill(Infinity));

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

let best = Infinity;
// 枚举 len 的所有真因子 d (1 <= d < len 且 len % d == 0)
// 注意:d = len 排除,因为要求真因子
for (let d = 1; d < len; d++) {
if (len % d !== 0) continue;

let changes = 0;
// 对于每个起始偏移 start (0 ~ d-1)
for (let start = 0; start < d; start++) {
// 收集该轨的所有下标: start, start+d, start+2d, ... 且 <= r
// 使用双指针从两端往中间配对
let i = l + start;
let j = 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. 动态规划:将字符串分成 k 段 ----------
// dp[i][c] : 将前 i 个字符 (s[0..i-1]) 分成 c 段的最少修改次数
const dp = Array.from({ length: n + 1 }, () => new 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++) { // 至少需要 c 个字符
// 枚举最后一段的起始位置 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 且 d | L),使得将所有下标按 mod d 分组后,每组都是一个回文串,则称该字符串是半回文。
· 修改次数计算:
· 对于每个 d,将原串映射成 d 条轨道。
· 每条轨道内的字符必须回文,所以统计轨道内对称位置不同的对数。
· 所有轨道的总不同对数就是按此 d 划分需要的修改次数。
· 取所有真因子 d 中的最小值。

2. 为什么预处理是必要的?

如果直接在 DP 里对每个子串实时计算半回文代价,会重复计算大量子串,复杂度爆炸。预处理 O(n^3) 在 n ≤ 200 时可行(约 800 万次操作),DP 额外 O(n^2 * k) 也 ok。

3. 动态规划细节

· 状态 dp[i][c]:前 i 个字符分成 c 段的最小代价。
· 转移:枚举最后一段的开始位置 j(前 j 个字符分成 c-1 段),加上子串 s[j..i-1] 的半回文代价。
· 初始化 dp[0][0] = 0,其他为无穷大。
· 答案 = dp[n][k]。

4. 边界条件

· 若 k > n 理论上无法划分(题目不会出现)。
· 若某个子串无法变成半回文(如长度 1),则 cost 保持 Infinity,DP 时自动跳过。

复杂度

· 时间:预处理 O(n^3),DP O(n^2 * k),实测 n=200 时能通过。
· 空间:O(n^2) 存储 cost,加上 DP 表 O(n*k)。

测试样例

```javascript
console.log(minimumChanges("abcde", 2)); // 输出:?
console.log(minimumChanges("aabbaa", 3)); // 输出:?
```

你可以自行运行验证。

如果你需要进一步了解如何优化因子的枚举或提前剪枝,或者对半回文定义有疑问,欢迎继续提问。

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

相关文章:

  • 微信小程序getPhoneNumber报错102?别慌,这可能是你的账号类型搞错了
  • TRAE与MCPServer高效集成实战指南
  • Viking AI 搜索 CLI 正式发布:会说话,就能做搜索推荐
  • 道本科技与DeepSeek联合解决方案:助力国央企合同管理数字化转型升级白皮书
  • 告别命令行恐惧:用Blue Kenue可视化TELEMAC V8P4在Windows 10下的计算结果
  • 第31篇 k8s之Ingress 进阶:TLS、重写与认证
  • DevSecOps建设之移动端自动化技能Appium
  • C#写的水准测量快速平差小工具,带闭合差分配和精度分析
  • Halcon变异模型(Variation Model)的三种模式(standard/robust/direct)到底怎么选?看完这篇就懂了
  • 手把手教你用SAM模型处理CHAOS医学CT图像:从DCM到NPZ的完整预处理流程
  • 别再自己造轮子了!用ThingsBoard开源平台,5步搞定一个物联网应用原型
  • 可重启序列:多核微处理器性能提升利器,最高让性能提升百万倍!
  • Java 程序员第 40 阶段10:从零搭建 Java 大模型完整项目,生产环境验证与持续迭代
  • 3分钟搞定NVIDIA显卡色彩校准:让宽色域显示器回归真实色彩
  • 第32篇 k8s 之 配置管理:ConfigMap 详解
  • 7-7. 开题报告等文档资料学校会查重吗?
  • 深入QNX Screen:利用screencmd命令行工具调试与动态修改窗口属性
  • 【无】2000-2024年各省人力资本水平数据(含原始数据+计算过程+计算结果)
  • 毕设直用|Python版Paillier加密联邦聚合系统(带双端一键启动脚本)
  • PC屏保画报广告5月档无与伦比的夏日经济
  • 别再只盯着ACOS了!亚马逊广告报告里的ROAS、ACOAS、ASOAS,哪个才是你该关心的核心指标?
  • AI 编程浪潮下,Zig 等开源项目为何坚守「拒绝 AI 代码」?
  • imx6ull 开发板,手机,MQTT 物联网通信实验。
  • OpenHarmony 4.0 Release版源码下载后,你的50G硬盘里到底多了些什么?
  • 【Agent】OpenCode 接入 DeepSeek-V4-Pro 开启1M上下文 保姆级教程
  • 用Python动手推导:能量守恒、勾股定理与机器学习损失函数之间的奇妙联系
  • 数字信任技术全景:从密码学基础到隐私保护实战
  • DeepSeek LeetCode 2911. 得到 K 个半回文串的最少修改次数 TypeScript实现
  • 【智能制造】- APS系列|16 生产计划与生产排程:核心概念与分类
  • Java 集成 LibreOffice 实现离线文档转换:Windows 与 Linux 环境详解