题目信息:
360截图18750812116111149.png

滑动窗口解法:

	/**
	 * 滑动窗口解法
	 * @param arr
	 * @param k
	 * @return
	 */
	public static int getNumberBySlideWindow(int[] arr, int k) {
		int right = 0; // 窗口右指针
		int left = 0; // 窗口左指针
		int oddNum = 0; // 窗口中当前奇数的个数
		int result = 0; // 最优子数组的数量
		
		// 滑动窗口的右边界不能超过数组的边界
		while (right < arr.length) {
			// 从左往右移动窗口右指针,让窗口变大(或者向右滑动), 并统计窗口中奇数的个数
			if (arr[right++] % 2 != 0) {
				oddNum++;
			}
			
			// 需要实时判断当前的滑动窗口中是否已经存在了足够的奇数
			if (oddNum == k) {
				// 如果当前滑动窗口中已经有足够的奇数了,则可以计算当前滑动窗口中可能存在的最优子数列
				// 首先,当前right指向的位置肯定是一个奇数,但奇数后面如果还有偶数,则也是可以加入到最优子数列中的
				// 所以,我们要找到下一个奇数的位置,计算出两个奇数之间有多少个偶数
				int temp = right;
				while (right < arr.length && arr[right++] % 2 == 0);
				// 窗口右边的偶数的个数
				int rightEvenCount = right - temp;
				
				// 同样,我们需要计算窗口右边的偶数个数
				int leftEvenCount = 0;
				while(arr[left++] % 2 == 0) leftEvenCount++; // left指针遇到第一个奇数后停止
				
				// 那么这个滑动窗口中存在最优子数组的个数为:
				result += ((leftEvenCount + 1) * (rightEvenCount + 1));
				
				// 计算完成后,left要往前移动一步,但它此时指向的是一个奇数,会导致滑动窗口中的奇数少一个
				left++;
				oddNum--;
			}
		}
		
		return result;
	}

前缀和解法:

	/**
	 * 前缀和的解法
	 * @param arr
	 * @param k
	 * @return
	 */
	public static int getNumberOfSubarrays(int[] arr, int k) {
		// 最优子数列的数量
		int result = 0; 
		// 奇数个数的前缀和
		int sum = 0; 
		// 对应前缀和的个数, 例子:
		// 数组 1 3 2 3 1, 
		// 取数组的前x项, 比如x=1时,只有一个奇数,则 sum = 1,而且只有一个奇数的也只有1种情况;
		// 比如x=2时, 有两个奇数,则 sum = 2, 且也只有一种情况。
		// 比如x = 3 时,依然有两个奇数, 则 sum = 2, 这时情况有两种了。
		// ....
		int[] map = new int[arr.length+1];
		// 没有奇数的情况有一种,空串的情况下,是没有奇数的。
		map[0] = 1;
		
		// 遍历数组
		for (int i = 0; i < arr.length; i++) {
			// 遇到奇数,则前缀项中奇数的个数+1;
			if (arr[i] % 2 != 0) sum++;
			// 对应的sum的情况也会加1;
			map[sum]++;
			
			//这里非常关键,如果当前的sum,即前缀项中的奇数个数已经超过k了,说明前缀项中肯定能找到最优子
			if (sum - k >= 0) {
				// 那么最优子数列的数量有多少个呢?
				// 可以拿 2 4 1 3 , k = 1 来举例, x表示遍历的索引:
				// 遍历到 x = 0时,map[0] = 2 (因为初始条件map[0] = 1 ,而 arr[x] = 2不是奇数,所以map[0]++ = 2;
				// 遍历到 x = 1时, map[0] = 3 (同样时因为 arr[x] = 4,不是奇数,map[0]++ = 3;
				// 遍历到 x = 2时, map[1] = 1 (因为 arr[x] = 1 ,是奇数, map[1]++ = 1;
				// 上面的条件判断成立:sum - k = 1 - 1 = 0 >=0; 
				// 这里为何是取map[sum-k]呢?可以这样理解:sum 代表 当前 奇数的个数, k代表最优子数组需要的奇数的个数, sum - k 就代表不需要的奇数的个数。
				// 那么像一个滑动窗口一样,k是固定的,就是要看sum-k个奇数的时候有多少种情况。
				result += map[sum - k];
			}
		}
		
		return result;
	}

Q.E.D.