
本文详解如何修复因数组引用导致的逻辑错误,通过深拷贝避免副作用,正确统计最高分和最低分的破纪录次数。
本文详解如何修复因数组引用导致的逻辑错误,通过深拷贝避免副作用,正确统计最高分和最低分的破纪录次数。
在解决经典的「Breaking Records」(破纪录)问题时,核心目标是:给定一个整数数组表示连续比赛得分,统计打破最高分纪录的次数(严格大于此前所有成绩)和打破最低分纪录的次数(严格小于此前所有成绩),首项不计入统计。
原代码看似逻辑清晰——分别定义 HP()(High Peak)和 LP()(Low Peak)函数遍历数组、剔除非峰值元素、再计数。但实际运行结果错误(如输入 [10,5,20,20,4,5,2,25,1] 输出非预期的 [?, ?]),根本原因在于 JavaScript 中数组是引用类型。
观察原代码关键片段:
function HP(array) {
var b = array; // ❌ 错误:b 与 scores 指向同一内存地址
// ... 后续对 b 的 splice() 操作会直接修改原始 scores 数组!
}
当 HP() 执行 b.splice() 时,由于 b = array 是浅赋值,原始 scores 数组被意外修改;紧接着 LP() 接收的已是残缺数组,导致低分统计完全失真——这正是“单独运行函数正常,合起来就出错”的根源。
✅ 正确做法:使用扩展运算符 [...array] 创建独立副本,确保两次遍历互不影响:
function HP(array) {
var b = [...array]; // ✅ 创建新数组,隔离副作用
var temp = b[0];
for (let i = 1; i b[i]) {
b.splice(i, 1);
i--; // 回退索引以补偿删除
} else {
temp = b[i]; // 更新当前最高分基准
}
}
// 去重并统计严格大于首个元素的次数(即新高点)
const unique = [...new Set(b)];
return unique.filter(val => val > unique[0]).length;
}
function LP(array) {
var a = [...array]; // ✅ 同样创建副本
var temp = a[0];
for (let j = 1; j val <p>不过,上述去重+过滤逻辑仍显冗余。更简洁、高效且符合题意的实现应<strong>一次遍历完成统计</strong>,无需修改原数组:</p><pre class="brush:php;toolbar:false;">function breakingRecords(scores) {
if (scores.length maxRecord) {
maxRecord = scores[i];
highCount++;
}
if (scores[i] <p>⚠️ 关键注意事项:</p>
- 引用 vs 值语义:始终警惕对象/数组赋值默认为引用传递,需用 [...arr]、Array.from() 或 slice() 显式拷贝;
- 索引维护:splice() 会改变数组长度,循环中删除元素必须手动调整索引(如 i--),否则跳过后续项;
- 题目语义:[2, 4] 中 2 指突破最高分(20 → 25),4 指突破最低分(5 → 4 → 2 → 1),首项 10 是初始基准,不参与计数;
- 性能优化:避免多次遍历、去重和嵌套过滤,单次线性扫描(O(n))即可达成最优解。
综上,修复引用副作用是解决本题的第一步,而采用一次遍历的贪心策略,则是写出健壮、高效、可读性强的生产级代码的关键。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











