零、题目内容
一、写在前面
本人并没有学过滑动窗口算法,因此在这次周赛(本题为周赛赛题)后,看了很多大佬们写的题解。可能是自己理解力实在太差,大概花了一个多小时看题解才看懂,实在太难受了。
因此
想通过画图增强自己的理解能力,同时便于后人(理解力相对较差的哥们)更好理解这道题的解法。
二、思路
2.1 预计算
若有N个相同的值,有多少对相同的值?
相同的个数 相同的对数
1 0
2 1
3 3
4 6
5 10
...
自己想到的一个通用公式是:N * (N - 1) / 2
看了别人的题解:发现可以通过累加实现,这种规律会让思路更加清晰,也会让代码看起来更整洁一些, 规则如下:
相同的个数 相同的对数 上一个数量的对数 上一个相同的个数
1 0
2 1 = 0 + 1
3 3 = 1 + 2
4 6 = 3 + 3
5 10 = 6 + 4
2.2 核心思路
定义i,j表示数组的长度(初始值为0),依次移动i、j构成的子数组,查看是否符合题目所需要的条件。
1.若i到j形成的数组不满足条件,则j++,继续执行
2.若i到j形成的数组满足条件,则满足条件的子数组有length - j个,
然后i++,查看后续子数组是否满足条件。
2.1 若满足条件,继续i++
2.2 若不满足条件,则j++
图解:为什么i到j形成的数组满足条件满足条件的子数组有(length-j)个?
图示核心思路
三、代码(java)
- 我们需要拿一个map来存储某个数字相同的个数。
- 然后通过相应个数进行判断是否该子数组满足条件。
- 循环时,以j为主,当满足条件时开始i++,然后按照核心思路的写出代码即可。
public static long countGood(int[] nums, int k) {
HashMap<Integer, Integer> hashMap = new HashMap<Integer, Integer>();
int i = 0, j = 0, tempSum = 0, length = nums.length;
long count = 0;
while (i < nums.length && j < nums.length) {
// 设置默认值并累加相应的值
// 找规律:第一次出现时,tempSum加0
// 第二次出现时,tempSum加1
// 第i次出现时,tempSum加i - 1
tempSum += hashMap.getOrDefault(nums[j], 0);
if (hashMap.containsKey(nums[j])) {
hashMap.put(nums[j], hashMap.get(nums[j]) + 1);
} else {
hashMap.put(nums[j], 1);
}
while (tempSum >= k) {
count = count + length - j; // 枚举画图,往右延伸的所有数组均可成立
tempSum -= hashMap.get(nums[i]) - 1; // i移动后,需要减回对应的值,即:当前值 - 1
hashMap.put(nums[i], hashMap.get(nums[i]) - 1);
i++;
}
j++;
}
return count;
}