地址 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; } };