题目
- 给定n个正整数组成的数组,求平均数正好等于 k 的最长连续子数组的长度。
输入描述
- 第一行输入两个正整数n和k,用空格隔开。
- 第二行输入n个正整数ai,用来表示数组。
1≤n≤200000
1≤k,ai≤10^9
输出描述
如果不存在任何一个连续子数组的平均数等于k,则输出-1。
否则输出平均数正好等于 k 的最长连续子数组的长度
示例
5 2
1 3 2 4 1
3
思路
暴力思路
- 卡大数据的样例,按照题目的思路:将所有可以组合的区间都计算一遍,除以其中包含的元素个数
学习思路
- 问题转化:多个数相加可以整除k,那么可以将数组中的每一个元素减去k,得到的数组中的元素相加为0.
- 此时,就将问题转化为:找到数组中连续的子数组和为0的最长长度
- 还可以再转换为:寻找区间为0的最长连续子区间
- 说到“子区间”,那么一定不要将所有全部的区间都枚举一遍,尽量的将计算过的利用起来,避免重复计算
- 考虑:前缀和方法,自然也就是连续的子区间
- 通过前缀和将区间的值记录下来,需要哪个区间的值,直接作差即可
- 那么如何才能找到区间和为0的区间呢?
- 2个区间值是相同的和,作差后,剩余下的区间的值即为0
- 举例:
数组:[4, 2, 7, 6] k = 5
- 步骤一:给数组所有元素统一减去k,得到
数组:[-1, -3, 2, 1]
。此时我们可以分析针对这个数组中后半部分[-3, 2, 1]
最长的连续子区间,且总和为0;验证原数组:2 +7 +6 = 15 / 3 = 5
,是符合要求的
- 步骤二:针对减去
k
后,得到的数组,计算前缀和,前缀和数组 = [0, -1, -4, -2, -1]
(注:区间和第一个元素为0,对下标的维护),其中区间结果为-1的出现了2次,即:数组中第0(下标)个数的区间 与 数组中第3(下标)个数到第0个数的区间
,2个区间相减,剩下区间内第3、2、1
的元素,即:最长的连续区间长度为3
实现代码
const rl = require("readline").createInterface({ input: process.stdin });
var iter = rl[Symbol.asyncIterator]();
const readline = async () => (await iter.next()).value;
void async function () {
let n,k,tokens;
while(line = await readline()){
tokens = line.split(' ');
if(!n || !k) {
n = tokens[0],k = tokens[1];
}
}
tokens = tokens.map(item => {
return Number(item) - k;
})
console.log(tokens)
let ans = -1, map = new Map(), len = tokens.length, pre = 0;
map.set(0, 0)
for(let i = 1; i <= len; i++) {
pre = tokens[i - 1] + pre;
console.log(pre)
if(map.has(pre)){
ans = Math.max(ans, i - map.get(pre))
}else {
map.set(pre, i);
}
}
console.log(ans)
}()
考察