1248. 統計「優美子數組」
題目來源:https://leetcode-cn.com/problems/count-number-of-nice-subarrays
題目
給你一個整數數組 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
解題思路
思路:雙指針(滑動窗口)
首先,理解題目的內容。
【如果某個連續子數組中恰好有 k 個奇數數字,我們就認爲這個子數組是「優美子數組」。】
這個就是【優美子數組】的定義,需要注意,子數組需連續,且有 k 個奇數數字。
那麼在這裏轉換下思路:也就是先找到連續 k 個奇數的子數組,那麼前後添加任意個偶數(注意只能是偶數,可以是 0 個),這裏都能構建【優美子數組】。
那麼具體的算法:
- 定義雙指針,先移動右指針,擴大滑動窗口,使數組含有 k 個奇數;
- 當滑動窗口包含 k 個奇數時,這個時候考慮構建【優美子數組】:
- 計算滑動窗口第一個奇數左邊的偶數個數
left_even_count
。如前面所述,這裏偶數可以是 0 個。所以計算出來的數目需加 1。 - 計算滑動窗口第 k 個奇數右邊的偶數個數
right_even_count
。與上面的一樣,計算數目需加 1。
- 計算滑動窗口第一個奇數左邊的偶數個數
- 因爲題目要求,【優美子數組】爲含有連續包含 k 個奇數的子數組。那麼在最簡子數組的基礎上左右添加偶數元素同樣成立。那麼這裏的組合數爲
(left_even_count + 1) * (right_even_count + 1)
。
具體實現代碼如下。
代碼實現
class Solution:
def numberOfSubarrays(self, nums: List[int], k: int) -> int:
# 定義雙指針
left, right = 0, 0
# 統計奇數個數
odd_count = 0
# 返回結果
ans = 0
# 數組長度
length = len(nums)
while right < length:
# 先移動右指針,統計奇數個數
if nums[right] % 2 == 1:
odd_count += 1
right += 1
# 當滑動窗口有 k 個奇數時,統計優美子數組個數
if odd_count == k:
# 這個時候向右邊擴大窗口,統計偶數個數,
# 遇到奇數或者越界則停止
sign = right
while right < length and nums[right] % 2 == 0:
right += 1
# 計算窗口右邊偶數個數
right_even_count = right - sign
# 統計窗口右邊的偶數個數後,
# 現在統計窗口左邊的偶數個數
left_event_count = 0
while nums[left] % 2 == 0:
left_event_count += 1
left += 1
# 現在計算組合數,添加到結果中
# 注意:偶數個數可以爲 0 個,
# 所以前面計算的左右偶數個數需加 1
ans += (left_event_count + 1) * (right_even_count + 1)
# 這個時候,數組後續可能還有其他的組合
# left 在此時指向的是第一個奇數,所以向後移動一步
left += 1
odd_count -= 1
return ans
實現結果
以上就是使用雙指針(滑動窗口)的思路,運用固定含 k 個奇數的窗口,左右尋找偶數,進行組合的方法,用以解決《1248. 統計「優美子數組」》問題的主要內容。
歡迎關注微信公衆號《書所集錄》