LeetCode 1248 统计优美子数组

LeetCode 1248 统计优美子数组

🟡 中等 https://leetcode.cn/problems/count-number-of-nice-subarrays/description/

可以使用动态规划求解: 以 [2,2,2,1,2,2,1,2,2,2] ,限制2个1为例:

class Solution {

public:

    int numberOfSubarrays(vector<int>& nums, int k) {

        vector<int> pre(nums.size()+1,0);

        int count = 0;

        for(int i = nums.size()-1;i>=0;i--){

            if(nums[i]%2==0){

                pre[i] = pre[i+1];

                count++;

            }else{

                pre[i]=count+1;

                count=0;

            }

        }

        for(int i = 2;i<=k;i++){

            vector<int> current(nums.size()+1,0);

            for(int j = nums.size()-1;j>=0;j--){

                if(nums[j]%2==0){

                    current[j] = current[j+1];

                }else{

                    current[j] = pre[j+1];

                }

            }

            pre = current;

        }

        return accumulate(pre.begin(),pre.end(),0);

    }

};

时间复杂度:O(n*k) ,超时了。

滑动窗口

在找到窗口内奇数个数为k时,设置tmp,假装滑动,我们要找到以i结尾的所有合法子数组的左边界,左边界可能时当前的left,也可能时右边第一个奇数。

使用tmp滑动到第一个奇数,所以while条件设置相反的,停在奇数后,求长度即可。

class Solution {

public:

    int numberOfSubarrays(vector<int>& nums, int k) {

        int left = 0;

        int res = 0;

        int window_count = 0;

        for(int i = 0;i<nums.size();i++){

            if(nums[i]%2==1){

                window_count++;

            }

            while(window_count>k){

                if(nums[left]%2==1) window_count--;

                left++;

            }

            if(window_count==k){

                int tmp = left;
			
                while(nums[tmp]%2==0){

                    tmp++;

                }

                res+=tmp-left+1;

            }

        }

        return res;

    }

};

其他

https://leetcode.cn/problems/count-number-of-nice-subarrays/solutions/212966/count-number-of-nice-subarrays-by-ikaruga/

class Solution {

public:

    int numberOfSubarrays(vector<int>& nums, int k) {

        vector<int> odd_index;

        odd_index.push_back(-1);

        int pre_odd = 1;

        int ans = 0;

        for(int i = 0;i<=nums.size();i++){

            if(i==nums.size()||nums[i]%2==1) odd_index.push_back(i);

            if(odd_index.size()-1-pre_odd+1==k+1){

                int left = odd_index[pre_odd]-odd_index[pre_odd-1];

                int right = i-1-odd_index[odd_index.size()-2]+1;

                ans +=left*right;

                pre_odd++;

            }

        }

        return ans;

    }

};