每日一题 LeetCode

作者:LeetCode-Solution
链接:https://leetcode-cn.com/problems/count-number-of-nice-subarrays/solution/tong-ji-you-mei-zi-shu-zu-by-leetcode-solution/

统计「优美子数组」

题目描述

给定一个整数数组 nums 和一个整数 k。

如果某个连续子数组中恰好有 k 个奇数数字,就认为这个子数组是「优美子数组」。

请返回这个数组中「优美子数组」的数目。
在这里插入图片描述

题解

  1. 单独建立一个 odd \textit{odd} odd 数组来记录第 i 个奇数的下标。那么我们可以枚举奇数,假设当前枚举到第 i 个,那么 [ odd [ i ] , odd [ i + k − 1 ] ] [\textit{odd}[i],\textit{odd}[i+k-1]] [odd[i],odd[i+k1]] 这个子数组就恰好包含 k 个奇数。
  2. 由于奇数和奇数间存在偶数,所以一定存在其他子数组 [ l , r ] [l,r] [l,r] 满足 [ l , r ] [l,r] [l,r] 包含 [ odd [ i ] , odd [ i + k − 1 ] ] [\textit{odd}[i],\textit{odd}[i+k-1]] [odd[i],odd[i+k1]] [ l , r ] [l,r] [l,r]里的奇数个数为 k 个。
  3. 因此对于第 i 个奇数,符合条件的 [ l , r ] [l,r] [l,r] 的个数:
    ( odd [ i ] − odd [ i − 1 ] ) ∗ ( odd [ i + k ] − odd [ i + k − 1 ] ) (\textit{odd}[i] - \textit{odd}[i - 1]) * (\textit{odd}[i + k] - \textit{odd}[i + k - 1]) (odd[i]odd[i1])(odd[i+k]odd[i+k1])
    只需要遍历一遍 odd \textit{odd} odd 数组即可求得最后的答案,注意边界的处理。

复杂度分析
时间复杂度: O ( n ) O(n) O(n),其中 n 为数组的大小。遍历 odd \textit{odd} odd 数组最坏情况下需要 O ( n ) O(n) O(n)的时间。
空间复杂度: O ( n ) O(n) O(n),其中 n 为数组的大小。 odd \textit{odd} odd 数组需要 O ( n ) O(n) O(n) 的空间。

方法二:前缀和 + 差分

在这里插入图片描述
在这里插入图片描述
复杂度分析
时间复杂度: O ( n ) O(n) O(n),其中 n 为数组的大小。
空间复杂度: O ( n ) O(n) O(n),其中 n 为数组的大小。频次数组 cnt \textit{cnt} cnt 记录的最大值不会超过 n ,因此只需要额外的 O ( n ) O(n) O(n) 的空间

代码

class Solution {
public:
    int numberOfSubarrays(vector<int>& nums, int k) {
        /*
        // 方法一:建立odd数组记录奇数所在位置的下标
        int n = nums.size();
        int odd[n+2], ans = 0, index = 0;
        for(int i = 0; i < n; i++){
            if(nums[i] & 1)
                odd[++index] = i;
        }
        odd[0] = -1;
        odd[++index] = n;
        for(int i = 1; i + k <= index; i++)
            ans += (odd[i]-odd[i-1])*(odd[i+k]-odd[i+k-1]);
        return ans;
        */

        // 方法二:前缀和+差分
        int n = nums.size();
        cnt.resize(n + 1, 0);
        int odd = 0, ans = 0;
        cnt[0] = 1;
        for(int i = 0; i < n; i++){
            odd += nums[i] & 1;
            ans += odd >= k ? cnt[odd - k] : 0;
            cnt[odd] += 1;
        }
        return ans;
    }
private:
    vector<int> cnt;    

};

小结

数组:int a[n]; 一种内置的数据类型。数组是存放类型相同的对象的容器,数组的大小确定不变,不能随意向数组中增加元素。
向量:vector a;类型相同的对象的容器,vector的大小可以变化,可以向数组中增加元素。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值