双指针 02

114 阅读1分钟

LeetCode. 1248

LeetCode.1248

题目链接

/*
 *   (双指针) 
 *  双指针扫描 r 在前,l 在后。
 *  如果当前位置是奇数,则更新计数器,如果当前 [l, r] 有了恰好 k 个奇数,则移动 l 直到不满足,期间统计出长度为 tot。
 *  让 ans 累加 tot。
 *  如果当前位置是偶数,则说明答案和上一次是奇数的时候一样,直接让 ans 累加上一次的 tot。
 *  因为偶数没有影响
 *
 *  时间复杂度
 *  每个位置最多遍历两次,故时间复杂度为 O(n)。
 *
 *  空间复杂度
 *  仅需要常数的额外空间。
 */

class Solution {
	public int numberOfSubarrays(int[] nums, int k) {
		int n = nums.length;

		int cnt = 0, tot = 0, ans = 0;
		for (int r = 0, l = 0; r < n; r++) {
			if (isOdd(nums[r])) {
				cnt++; 					// 记录[r,l]内奇数的个数
				if (cnt == k)
					tot = 0; 			// [r,l]内正好有k个奇数初始化数据,重新计算tot,最终累加到ans

				while (cnt == k) {
					tot++; 				// l右移奇数则退出循环,偶数不影响,继续增加子数组
					if (isOdd(nums[l])) // 在l向右移动的过程中,如果遇到奇数,则cnt--
						cnt--; 			// 因为进入此if,左端点是奇数,l右移碰到奇数
					l++; 				// 不成立了,所以要退出,在这之前把左端点奇数减掉
				} 						// 为下次做准备
				ans += tot;
			} else {
				ans += tot;
			}
		}

		return ans;
	}

	private boolean isOdd(int n) {
		return n % 2 == 1; 				// 判断是否为奇数
	}
}