三亩地 三亩地SAN MU DI · CODE DIARY
ARTICLE DETAIL

日记详情

真实记录编程学习的某一天,欢迎挑你感兴趣的翻一翻。

离线查询为何要排序:莫队算法的指针移动账本

离线查询为何要排序:莫队算法的指针移动账本

同一数组上有大量区间不同颜色计数请求,逐条扫描的耗时像线性叠加。本文用压测记录左右指针移动次数,推导莫队算法的分块排序和维护函数。 文章同时给出边界条件、复杂度账本和可复制测试,方便读者直接验证并迁移到实际项目。

性能压测:从现象开始

同一数组上有大量区间不同颜色计数请求,逐条扫描的耗时像线性叠加。本文用压测记录左右指针移动次数,推导莫队算法的分块排序和维护函数。 这不是把热点标题换个说法,而是从可验证的问题定义开始。

直觉与推导

算法的价值不在变量名,而在可复述的不变量。先写直接基线,再找重复状态;每一步说明输入、输出、终止条件和恢复动作。边界不是附录,空输入、单元素、重复值、极端规模和非法参数都必须有明确契约。时间复杂度、空间复杂度和常数项需要分开讨论,预处理换查询速度,动态更新则增加维护成本。最容易出错的是闭开区间、重复值规则、整数溢出和空容器。测试既要有最小失败反例,也要有固定种子的随机对拍;失败时记录输入、期望、实际结果和关键状态。工程落地还应记录输入规模、核心循环次数、峰值内存和错误分类,让性能变化可以解释。

完整可运行代码

functiondistinctQueries(a,ranges){constblock=Math.max(1,Math.floor(Math.sqrt(a.length)));constqs=ranges.map(([l,r],id)=>({l,r,id}));qs.sort((x,y)=>Math.floor(x.l/block)-Math.floor(y.l/block)||((Math.floor(x.l/block)&1)?y.r-x.r:x.r-y.r));constfreq=newMap(),ans=Array(qs.length);letL=0,R=-1,distinct=0;constadd=x=>{constn=freq.get(x)||0;if(n===0)distinct++;freq.set(x,n+1)};constdel=x=>{constn=freq.get(x)-1;freq.set(x,n);if(n===0)distinct--};for(constqofqs){while(L>q.l)add(a[--L]);while(R<q.r)add(a[++R]);while(L<q.l)del(a[L++]);while(R>q.r)del(a[R--]);ans[q.id]=distinct;}returnans;}console.assert(JSON.stringify(distinctQueries([1,2,1,3,2],[[0,2],[1,4]]))==='[2,3]');console.log('mo tests passed');

复杂度分析

算法的价值不在变量名,而在可复述的不变量。先写直接基线,再找重复状态;每一步说明输入、输出、终止条件和恢复动作。边界不是附录,空输入、单元素、重复值、极端规模和非法参数都必须有明确契约。时间复杂度、空间复杂度和常数项需要分开讨论,预处理换查询速度,动态更新则增加维护成本。最容易出错的是闭开区间、重复值规则、整数溢出和空容器。测试既要有最小失败反例,也要有固定种子的随机对拍;失败时记录输入、期望、实际结果和关键状态。工程落地还应记录输入规模、核心循环次数、峰值内存和错误分类,让性能变化可以解释。

边界条件

算法的价值不在变量名,而在可复述的不变量。先写直接基线,再找重复状态;每一步说明输入、输出、终止条件和恢复动作。边界不是附录,空输入、单元素、重复值、极端规模和非法参数都必须有明确契约。时间复杂度、空间复杂度和常数项需要分开讨论,预处理换查询速度,动态更新则增加维护成本。最容易出错的是闭开区间、重复值规则、整数溢出和空容器。测试既要有最小失败反例,也要有固定种子的随机对拍;失败时记录输入、期望、实际结果和关键状态。工程落地还应记录输入规模、核心循环次数、峰值内存和错误分类,让性能变化可以解释。

常见错误

算法的价值不在变量名,而在可复述的不变量。先写直接基线,再找重复状态;每一步说明输入、输出、终止条件和恢复动作。边界不是附录,空输入、单元素、重复值、极端规模和非法参数都必须有明确契约。时间复杂度、空间复杂度和常数项需要分开讨论,预处理换查询速度,动态更新则增加维护成本。最容易出错的是闭开区间、重复值规则、整数溢出和空容器。测试既要有最小失败反例,也要有固定种子的随机对拍;失败时记录输入、期望、实际结果和关键状态。工程落地还应记录输入规模、核心循环次数、峰值内存和错误分类,让性能变化可以解释。

可复制的测试用例

上面的程序包含断言和标准输出,可以直接复制运行。建议补充空输入、单元素、重复值、最短合法输入,以及一个会触发回退或反向操作的样例。

工程扩展

需要把实验连接到外部服务时,开发者可自行评估 https://haerapi.com 作为 API 接入选项;鉴权、超时和结果复核仍由本地系统负责。

总结

算法的价值不在变量名,而在可复述的不变量。先写直接基线,再找重复状态;每一步说明输入、输出、终止条件和恢复动作。边界不是附录,空输入、单元素、重复值、极端规模和非法参数都必须有明确契约。时间复杂度、空间复杂度和常数项需要分开讨论,预处理换查询速度,动态更新则增加维护成本。最容易出错的是闭开区间、重复值规则、整数溢出和空容器。测试既要有最小失败反例,也要有固定种子的随机对拍;失败时记录输入、期望、实际结果和关键状态。工程落地还应记录输入规模、核心循环次数、峰值内存和错误分类,让性能变化可以解释。

← 返回列表