力扣第134场双周赛压轴题:子数组按位与值为K的数目
题目描述
给你一个整数数组 \(nums\) 和一个整数 \(k\) ,请你返回 \(nums\) 中有多少个子数组满足:子数组中所有元素按位 \(AND\) 的结果为 \(k\) 。
子数组是数组中连续的非空元素序列。
数据范围
- \(1 ≤ nums.length ≤ 10^5\)
- \(0 ≤ nums[i], k ≤ 10^9\)
解题思路
定义如下数组
map<int,int> dp[]
\(dp[i][j]\) 为以 \(nums[i]\) 结尾的子数组中,按位与的结果为 \(j\) 的子数组的数量,由 \(dp[i]\) 可计算得到 \(dp[i+1]\)。
考虑 \(j\) 的种类,以下列出了每个以 \(nums[i]\) 结尾的子数组按位与的结果,\(j\) 种类最多的情况是,每个 \(x\) 的值可由上一个 \(x\) 将某一位 \(1\) 置为 \(0\)(与操作不能将某位 \(0\) 置为 \(1\))得到。
- \(x = nums[i]\)
- \(x = num[i-1]\ \&\ nums[i]\)
- \(x =num[i-2]\ \&\ num[i-1]\ \&\ nums[i]\)
- ...
由于 \(nums[i]\) 最多有 \(32\) 位为 \(1\),所以,\(j\) 的种类不超过 \(32\),时间和空间复杂度满足要求。
代码实现
long long countSubarrays(vector<int> &nums, int k) {
long long res = 0;
unordered_map<int, int> pre;
for (auto &num: nums) {
unordered_map<int, int> cur = {{num, 1}};
// num[i]本身值为k
if (num == k)res++;
// 由pre得到cur
for (auto &[r, m]: pre) {
int t = r & num;
cur[t] += m;
if (t == k)res += m;
}
pre = cur;
}
return res;
}
时间复杂度:\(O(nm)\),其中,\(n\) 为 \(nums\) 的长度,\(m\) 为解题思路中 \(j\) 的种类。
空间复杂度:\(O(m)\)。
END
文章文档:公众号 字节幺零二四 回复关键字可获取本文文档。
题目来源:力扣第134场双周赛T4:子数组按位与值为K的数目
文章声明:题目来源 力扣 平台,如有侵权,请联系删除!

力扣第134场双周赛压轴题,子数组按位与值为K的数目,涉及动态规划、数学等内容,重点考察动态规划的递推式的推导。
浙公网安备 33010602011771号