LeetCode 1248. 統計「優美子數組」

地址 https://www.acwing.com/solution/leetcode/content/5801/算法

題目描述
給你一個整數數組 nums 和一個整數 k。數組

若是某個子數組中剛好有 k 個奇數數字,咱們就認爲這個子數組是「優美子數組」。spa

請返回這個數組中「優美子數組」的數目。code

示例 1:

輸入:nums = [1,1,2,1,1], k = 3
輸出:2
解釋:包含 3 個奇數的子數組是 [1,1,2,1] 和 [1,2,1,1] 。
示例 2:

輸入:nums = [2,4,6], k = 1
輸出:0
解釋:數列中不包含任何奇數,因此不存在優美子數組。
示例 3:

輸入:nums = [2,2,2,1,2,2,1,2,2,2], k = 2
輸出:16

提示:

1 <= nums.length <= 50000
1 <= nums[i] <= 10^5
1 <= k <= nums.length

算法1
暴力枚舉 就不說了 TLE了blog

好比
nums = [2,2,2,1,2,2,1,2,2,2], k = 2
暴力枚舉確定是
2 2 2 1 2 2 1
2 2 2 1 2 2 1 2
2 2 2 1 2 2 1 2 2
2 2 2 1 2 2 1 2 2 2索引

2 2 1 2 2 1
2 2 1 2 2 1 2
2 2 1 2 2 1 2 2
2 2 1 2 2 1 2 2 2leetcode

.....一共16組get

觀察規律
往滑動窗口方便考慮
我先計算出 開頭結尾都是奇數 符合K個奇數的數組
而後在計算左右兩邊能夠填寫的的偶數數目
最後的答案-子數組的數目 ,實際上是左邊能夠選擇的方案數乘以右邊能夠選擇方案數io

也就是基本數組1,2,2,1 向左右擴展。
左邊可填充的偶數乘以右邊可填充的偶數
(左邊能夠填充3個2 ,右邊能夠填充3個2, 再加上最基本數組的奇數開頭結尾也算是一種選擇)
因此最終結果就是 (3+1)*(3+1) = 16class

代碼

class Solution {
public:
    int numberOfSubarrays(vector<int>& nums, int k) {
        if (nums.size() < k) return 0; int ret = 0;
        vector<int> v;
        for (int i = 0; i < nums.size(); i++) {
            if (nums[i] % 2 != 0) v.push_back(i);
        }
        //獲得全部爲奇數的下標索引
        vector<pair<int, int>> vp;
        int i = 0;
        while (k + i <= v.size()) {
            int a = v[0 + i];
            int b = v[k + i - 1];
            vp.push_back({ a,b });
            i++;
        }

        //對於每一個剛恰好是K個奇數 且奇數開頭結尾的子數組 再進行計算
        for (int i = 0; i < vp.size(); i++) {
            int a = vp[i].first;
            int b = vp[i].second;
            //計算左邊有多少個偶數能夠添加進來
            if (i == 0) a = a+1;
            else {
                a = a - vp[i - 1].first;
            }
            //計算右邊有多少個偶數能夠添加進來
            if (i == vp.size() - 1) b = nums.size() - b;
            else {
                b = vp[i + 1].second - b;
            }

            ret += a * b;
        }
        return ret;
    }
};
相關文章
相關標籤/搜索