题意

给定一个数组和一个整型数字k,找出数组的一个连续子数组,其中包含k个奇数。返回子数组的个数。

思路

这道题的思路就是,先遍历数组,然后记录每个奇数的左边和右边的连续偶数的个数,得到一个新的数组。然后遍历通过滑动窗口的形式遍历新的数组,将窗口左侧的左边偶数个数与窗口右侧的右边偶数个数相乘就是结果

我们看一个例子

nums = 2,2,2,1,2,2,1,2,2,2, k = 2,结果是16个。

我们看到数组中一个包含两个1。我们可以得到一个新的数组描述如下图

Untitled

代表第一个1左侧有3个偶数,右侧有两个偶数,第二个1左侧有2个偶数,右侧有3个偶数。

但是我们发现按照窗口的计算规则是33 = 9, 与目标结果不一致。这里我们是忽略了一个情况,我们按照33计算都是以偶数开头和偶数结尾的,但是我们同样可以奇数开头,奇数结尾,例如1,2,2,1也是一个结果,但是我们没有计算进去。

所以我们在计算left的时候 left = 偶数个数+1,同理right = 偶数个数+1

// 定义存储左右连续偶数个数的结构体
type tmp1248 struct {
	left, right int
}

func numberOfSubarrays(nums []int, k int) int {
	ans := 0
	l := len(nums)
	indies := make([]tmp1248, 0)
	even := 0

	for i := 0; i < l; i++ {
		if nums[i]&1 == 0 {
			even++
			continue
		}
		// left can start with itself so, left = even+1
    // left = 偶数个数+1
		indies = append(indies, tmp1248{left: even + 1})
		li := len(indies)
    // 这里是更新前一个奇数的右边连续偶数个数
		if li > 1 {
			indies[li-2].right = even
		}
		even = 0
	}
	if len(indies) == 0 || k > len(indies) {
		return 0
	}
	li := len(indies)
	indies[li-1].right = even

	start := 0
	for ; start <= len(indies)-k; start++ {
		ans += indies[start].left * (indies[start+k-1].right+1)
	}
	return ans
}