统计中位数为K的子数组
给你一个长度为 n 的数组 nums ,该数组由从 1 到 n 的不同整数组成
另给你一个正整数 k ,统计并返回 nums 中的中位数等于 k 的非空子数组的数目
1. 前缀和 + 哈希
容易知道子数组必然包含数字k,其实就是列举包含k子数组,计算并且中位数为k的个数
同时列举两侧的复杂度是O(n2)级别,可以一侧先用哈希记录前缀和,只需遍历另一侧即可
左侧更小值 + 右侧更小值 = 左侧更大值 + 右侧更大值
变换一下即,左侧更小值-左侧更大值 = 右侧更大值 - 右侧更小值
先用哈希记录左侧不同数目值区间的个数,这里用前缀和,然后遍历右侧找满足条件的即可
class Solution {
public:
int countSubarrays(vector<int> &nums, int k) {
int pos = find(nums.begin(), nums.end(), k) - nums.begin(); //找k的位置
// i=pos 的时候 x 是 0,直接记到 cnt 中,这样下面不是大于 k 就是小于 k
unordered_map<int, int> cnt; //左侧区间各贡献值数量
cnt[0] = 1;
for (int i = pos - 1, x = 0; i >= 0; --i) { // 从 pos-1 开始累加 x
x += nums[i] < k ? -1 : 1; //小于贡献-1,大于贡献1 ,最终可以等于0或1
++cnt[x]; //记录左边贡献值,其实就是(i,pos)区间贡献值
}
// i=pos 的时候 x 是 0,直接加到答案中,这样下面不是大于 k 就是小于 k
int ans = cnt[1] + cnt[0];
for (int i = pos + 1, x = 0; i < nums.size(); i++) { // 从 pos+1 开始累加 x
x += nums[i] > k ? -1 : 1; //右侧贡献值
ans += cnt[x+1] + cnt[x];//匹配左侧值
}
return ans;
}
};