统计完全子数组的数目

给你一个由 正 整数组成的数组 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:暴力解

本来没想使用暴力解的,看着这个题目就像是双指针的问题。但是看着这个数据量,算了一下时间复杂度以及周赛的排名,还是默默写下了这个违背初心的解法。。。。关键:统计不同元素的数目时不要使用set,因为set的插入是O(log(n))的,需要使用map,插入的时间复杂度是O(1)的。

code1

class Solution {
public:
    //子数组的不同元素的数目和整个数组的不同元素数目相同
    //双重遍历判断是否符合条件
    
    int countCompleteSubarrays(vector<int>& nums) {
        
        int ans = 0;
        unordered_map<int,int> cnt;
        for(auto item : nums) cnt[item] ++;
        
        for(int i = 0;i < nums.size();i ++)
        {
            unordered_map<int,int> has;
            for(int j = i;j < nums.size();j ++)
            {
                has[nums[j]] ++;
                int len1 = cnt.size();
                int len2 = has.size();
                if(len1 == len2)
                {
                    ans += nums.size() - j;
                    break;
                }
            }
        }
        
        return ans;
    }
};

解题思路2:双指针

双指针的解法还是从朴素的写法出发,朴素解时间性能瓶颈主要是在右指针需要不断回溯,只要右指针不需要回溯即可。

  1. 枚举左指针为起点的完全子数组的数目
  2. 在枚举过程中右指针不回溯

code2

class Solution {
public:
    
    //子数组中不同元素的数目和原数组相同
    //双指针
    //如何思考呢?
    //朴素的解法:遍历每一个子数组判断子数组中是否符合条件
    //性能不高的原因在于右指针需要回溯
    //是否可以让右指针不需要回溯呢
    //是有方法可以使得右指针不需要回溯
    //比如找到一个符合条件的子数组时,就可以直接计算当前左指针为起点的完全子数组的数目
    //右移左指针,查找下一个一左指针为起点的子数组的数目
    //这个时候是不需要回溯的,只需要判断是不是缺少了不同的元素即可
    
    //写的过程还是不够丝滑很多细节都没能把握好
    //还是需要理清思路再下手写

    int countCompleteSubarrays(vector<int>& nums) {

        int ans = 0;
        int len = nums.size();

        unordered_map<int,int> cnt;
        for(auto item : nums) cnt[item] ++;

        int l = 0,r = 0;

        unordered_map<int,int> has;
        has[nums[r]] ++;
        while(l < nums.size() && r < nums.size())
        {
            while(has.size() < cnt.size())
            {
                r++;
                if(r < nums.size())
                    has[nums[r]] ++;
                else break;
            }

            if(has.size() == cnt.size()) ans += len - r;

            has[nums[l]] --;
            if(has[nums[l]] == 0) has.erase(nums[l]);
            l ++;
        }

        return ans;
    }
};
posted on 2023-07-31 21:03  huangxk23  阅读(74)  评论(0)    收藏  举报