滑动窗口——java版
用两个指针表示窗口的左边界(i)和有边界(j),用map存储窗口中每个元素出现的次数,当窗口中的元素满足条件时,则从窗口的左边界到右边界之后的所有区间也都满足条件。
(i, j)
(i, j+1)
(i, j+2)
..........
(i, n -1)
区间数为 n - j 个 。 接着左指针右移,缩小区间,每移动一次,如果窗口仍然满足条件,则又会有 n - j 个合法区间。继续右移左指针,直到窗口不满足条件,再移右指针去寻找下一个满足条件的窗口。

public class Main{
    public static void main(String[] args){
        Scanner cin = new Scanner(System.in);
        int n = cin.nextInt();
        int m = cin.nextInt();
        int[] a = new int[n];
        for(int i = 0; i < n; i++){
            a[i] = cin.nextInt();
        }
        
        Map<Integer, Integer> map = new HashMap<>();
        int i = 0;
        int j = 0;
        long count = 0;
        while(j < n && i <= j){
            int num = map.getOrDefault(a[j], 0) + 1;
            map.put(a[j], num);
            if(num == m){
                // 如果到j这里满足条件,那么所有j之后也都满足,直接计算有多少个区间
                count += n - j;
                // i向后移,直到区间不满足条件。每移动一次就会有新的合法区间
                while(i < j && map.get(a[i]) != num){
                    map.put(a[i], map.get(a[i]) - 1);
                    i++;
                    count += n - j;
                }
                if(map.get(a[i]) == num){
                    map.put(a[i], map.get(a[i]) - 1);
                    i++;
                }
            }
            j++;
        }
        System.out.println(count);
    }
}