leetcode 题解:6293. 统计好子数组的数目

95 阅读2分钟

零、题目内容

链接:leetcode.cn/problems/co…

image.png

一、写在前面

本人并没有学过滑动窗口算法,因此在这次周赛(本题为周赛赛题)后,看了很多大佬们写的题解。可能是自己理解力实在太差,大概花了一个多小时看题解才看懂,实在太难受了。

因此

想通过画图增强自己的理解能力,同时便于后人(理解力相对较差的哥们)更好理解这道题的解法。

二、思路

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)个?

image.png image.png

图示核心思路

image.png

三、代码(java)

  1. 我们需要拿一个map来存储某个数字相同的个数。
  2. 然后通过相应个数进行判断是否该子数组满足条件。
  3. 循环时,以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;
}

四、结果

image.png