力扣---6900. 统计完全子数组的数目

发布时间 2023-07-30 15:11:07作者: Owlwu

给你一个由  整数组成的数组 nums 。

如果数组中的某个子数组满足下述条件,则称之为 完全子数组 :

  • 子数组中 不同 元素的数目等于整个数组不同元素的数目。

返回数组中 完全子数组 的数目。

子数组 是数组中的一个连续非空序列。

 

示例 1:

输入:nums = [1,3,1,2,2]
输出:4
解释:完全子数组有:[1,3,1,2]、[1,3,1,2,2]、[3,1,2] 和 [3,1,2,2] 。

示例 2:

输入:nums = [5,5,5,5]
输出:10
解释:数组仅由整数 5 组成,所以任意子数组都满足完全子数组的条件。子数组的总数为 10 。

 

提示:

  • 1 <= nums.length <= 1000
  • 1 <= nums[i] <= 2000

 

周赛第二题。

可以想到,当一个子数组包含所有数字后,包含该子数组的所有数组都符合题意,且此数量分为三种:1. 以该数组左边界为边界。2. 以该数组右边界为边界。3. 该数组左右边界都不是边界。

固定一遍,向右遍历。可以发现,当固定左边界后,第三种情况一定会在之前的遍历就包含。而第二种情况,则是当前情况的答案数量。

滑动窗口。

class Solution {
//    滑动窗口。
//    维护窗口中的数据总是符合题意。
//    可以想到,以当前窗口左边界开始,以当前窗口为子窗口的字数组,共有 len - right 个(len指数组长度,right 指窗口右边界。)
    public int countCompleteSubarrays(int[] nums) {
        Set<Integer> set = new HashSet<>();
        for (int x : nums) {
            set.add(x);
        }
        int left = 0;
        int right = 0;
        int res = 0;
        int n = set.size();
        Map<Integer, Integer> map = new HashMap<>();
        while (right < nums.length) {
            if (map.size() < n) {
                map.put(nums[right], map.getOrDefault(nums[right], 0) + 1);
                right++;
                if (map.size() < n) {
                    continue;
                }
            }
            while (map.size() == n) {
                res += nums.length - right + 1;
                if (map.get(nums[left]) == 1) {
                    map.remove(nums[left]);
                } else {
                    map.put(nums[left], map.get(nums[left]) - 1);
                }
                left++;
            }

        }
        return res;
    }
}