給你一個整數數組 nums 和一個整數 k。
如果某個 連續 子數組中恰好有 k 個奇數數字,我們就認爲這個子數組是「優美子數組」。
請返回這個數組中「優美子數組」的數目。
示例 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
來源:力扣(LeetCode)
鏈接:https://leetcode-cn.com/problems/count-number-of-nice-subarrays
著作權歸領釦網絡所有。商業轉載請聯繫官方授權,非商業轉載請註明出處。
基本思想
滑動窗口
- 從頭到尾遍歷數組,找到滿足要求的最小子串
- 統計子串兩端連續偶數的個數,例如右邊 r 個,左邊 l 個,那麼由當前最小子串構成的優美子數組有 (r + 1) x (l + 1) 個
class Solution {
public:
int numberOfSubarrays(vector<int>& nums, int k) {
//找到一個優美子數組向兩端擴展,統計個數,用乘法的形式左面三個右面三個4x4
//然後再從第二個奇數所構成的優美數組向兩端擴展
if(nums.size() == 0 || k > nums.size())
return 0;
int res = 0;
deque<int> pos;
int s = 0;
for(int i = 0; i < nums.size(); ++i){
if(nums[i] & 1){
pos.push_back(i);//保存奇數的下標
}
if(pos.size() == k){
int l = pos.front() - s;//左面偶數的個數
int r = 0;
int k = i + 1;
//統計右面連續偶數的個數
while(k < nums.size() && ((nums[k] & 1) == 0)){
++r;
++k;
}
//cout << i << " " << l << " " << r << endl;
res += (l + 1) * (r + 1);
if(k == nums.size())
break;
s = pos.front() + 1;
pos.pop_front();
}
}
return res;
}
};
前綴和
- 統計以當前元素結尾的序列中優美子數組的個數
- 遍歷數組的過程中,統計前 i 個數字中奇數的個數
- 如果奇數的個數 odd大於等於 k,需要統計前 i 個數字中有多少個奇數個數爲odd - k的子序列,有幾個就說明能構成幾個優美子數組(這裏不太好理解,參考:官方題解)
class Solution {
public:
int numberOfSubarrays(vector<int>& nums, int k) {
vector<int> cnt(nums.size() + 1, 0);
cnt[0] = 1;
int odd = 0;//統計前i個數中奇數的個數
int res = 0;
for(int i = 0; i < nums.size(); ++i){
odd += (nums[i] & 1);
res += ((odd >= k ? cnt[odd - k] : 0));
cnt[odd]++;
}
return res;
}
};