用 sum 表示转换后的数组的前缀和,遍历过程中维护 sum 的值。对于 0 \le i < n,当遍历到下标 i 时,更新 sum 的值,然后执行如下操作:
如果 i < \textit{kIndex,则下标 i + 1 可以作为中位数等于 k 的非空子数组的开始下标,将 sum 在哈希表中的出现次数加 1;
如果 i \ge \textit{kIndex,则下标 i 可以作为中位数等于 k 的非空子数组的结束下标,从哈希表中获得前缀和 sum 的出现次数 prev}_0 与前缀和 sum} - 1 的出现次数 prev}_1,则以下标 i 作为结束下标且中位数等于 k 的非空子数组的数目是 prev}_0 + \textit{prev}_1,将答案增加 prev}_0 + \textit{prev}_1。
intcountSubarrays(vector<int>& nums, int k){ int n = nums.size(); int kIndex = -1; for (int i = 0; i < n; i++) { if (nums[i] == k) { kIndex = i; break; } } int ans = 0; unordered_map<int, int> counts; counts[0] = 1; int sum = 0; for (int i = 0; i < n; i++) { sum += sign(nums[i] - k); if (i < kIndex) { counts[sum]++; } else { int prev0 = counts[sum]; int prev1 = counts[sum - 1]; ans += prev0 + prev1; } } return ans; } };
staticinlineintsign(int num) { if (num == 0) { return0; } return num > 0 ? 1 : -1; }
intcountSubarrays(int* nums, int numsSize, int k) { int kIndex = -1; for (int i = 0; i < numsSize; i++) { if (nums[i] == k) { kIndex = i; break; } } int ans = 0; HashItem *counts = NULL; hashAddItem(&counts, 0, 1); int sum = 0; for (int i = 0; i < numsSize; i++) { sum += sign(nums[i] - k); if (i < kIndex) { hashSetItem(&counts, sum, hashGetItem(&counts, sum, 0) + 1); } else { int prev0 = hashGetItem(&counts, sum, 0); int prev1 = hashGetItem(&counts, sum - 1, 0); ans += prev0 + prev1; } } hashFree(&counts); return ans; }
funccountSubarrays(nums []int, k int)int { kIndex := -1 for i, num := range nums { if num == k { kIndex = i break } } ans := 0 counts := map[int]int{} counts[0] = 1 sum := 0 for i, num := range nums { sum += sign(num - k) if i < kIndex { counts[sum]++ } else { prev0 := counts[sum] prev1 := counts[sum-1] ans += prev0 + prev1 } } return ans }
funcsign(num int)int { if num == 0 { return0 } if num > 0 { return1 } return-1 }
复杂度分析
时间复杂度:O(n),其中 n 是数组 nums 的长度。遍历数组寻找正整数 k 所在下标需要 O(n) 的时间,遍历数组计算中位数等于 k 的非空子数组数目需要 O(n) 的时间。