跳转至

1248.统计优美子数组 (Medium)*

题目描述*

标签*

滑动窗口;前缀和;

思路 & 代码*

注意是恰有 k 个奇数,不是全是奇数。。。

滑动窗口,向右扩充直到窗口包含 k 个奇数,然后计算该窗口可以提供的子数组个数,统计第一个奇数左侧的偶数个数,这些偶数都可以去掉,形成一个新的子数组,同时还有第 k 个奇数右侧的偶数,也是这样。所以这段窗口可以提供的子数组数为 (leftEvevCnt + 1) * (rightEvenCnt + 1)。这样计算完成后右移左指针直到奇数个数为 k - 1,然后再向右扩充,直到结尾。

我们令奇数为 1,偶数为 0,那这个题就转换成了和为 k 的子数组个数。构造前缀和数组,然后统计 arr[i] - arr[j] = k 的个数,双重循环的时间复杂度为 O(n^2),优化可以参考两数之和,每遍历到一个前缀和 sum,累加 sum - k 的个数。

class Solution {
public:
    int numberOfSubarrays(vector<int> nums, int k) {
        int l = 0, r = 0, cnt = 0, res = 0;
        int len = nums.size();
        while(r < len) {
            if(nums[r++] & 1) {
                cnt++;
            }
            if(cnt == k) {
                int tmp = r;
                while(r < len && (nums[r] & 1) == 0) {
                    r++;
                }
                int rightEvenCnt = r - tmp;
                int leftEvenCnt = 0;
                while((nums[l] & 1) == 0) {
                    l++;
                    leftEvenCnt++;
                }
                res += (leftEvenCnt + 1) * (rightEvenCnt + 1);
                l++;
                cnt--;
            }
        }
        return res;
    }
};
class Solution {
public:
    int numberOfSubarrays(vector<int> nums, int k) {
        int len = nums.size();
        vector<int> prefixCnt(len + 1, 0);
        prefix[0] = 1;
        int sum = 0;
        int res = 0;
        for(auto& num : nums) {
            sum += num & 1;
            prefixCnt[sum]++;
            if(sum >= k) {
                res += prefixCnt[sum - k];
            }
        }
        return res;
    }
};

最后更新: July 23, 2022