📌  相关文章
📜  Q 查询的给定范围子数组中 2 的幂的元素计数(1)

📅  最后修改于: 2023-12-03 15:19:37.483000             🧑  作者: Mango

2 的幂元素计数问题介绍

给定一个数组和多个查询,每个查询包含一个范围 [L, R]。您需要回答在子数组 [L, R] 中有多少元素是 2 的幂次方。

示例

示例 1:

输入:

arr = [1, 2, 3, 4, 5],
queries = [[1, 1], [1, 2], [1, 3], [1, 4], [1, 5], [2, 4], [2, 5], [2, 2], [2, 3], [3, 3], [3, 4], [3, 5], [4, 4], [4, 5], [5, 5]]

输出:

[0, 1, 1, 2, 2, 1, 1, 1, 1, 0, 1, 1, 1, 2, 1]
解法

我们可以使用前缀和来解决这个问题。

我们可以使用一个二维数组 dp,其中 dp[i][j] 表示在数组中从 i 开始的连续的 2 的幂的个数,在范围 [i, j] 中的 2 的幂次方元素计数可以通过以下方式得到:

count = dp[j][j] - dp[i-1][j]

这里是标准前缀和的应用。

初始化 dp[0][i] 的值为 arr[i] 是否是 2 的幂次方,如果是,则 dp[0][i] = 1,否则为 0。

接下来,我们进行以下迭代:

dp[k][i] 的值为 dp[k-1][i] + dp[k-1][i+1],如果 i + 1 到 2^(k-1)-1 中的所有元素都是 2 的幂次方,那么 dp[k][i] 也是 2 的幂次方。

接下来,当我们计算查询时,我们可以通过以下公式计算在闭区间 [L, R] 中 2 的幂次方元素计数:

count = dp[log2(R-L+1)][L] - dp[log2(R-L+1)][R]
时间复杂度

我们首先需要 O(N logN) 的时间来计算 dp 数组。之后每个查询的时间复杂度为 O(1),所以总时间复杂度为 O(N logN + Q)。

代码片段
vector<int> count2Powers(vector<int>& arr, vector<vector<int>>& queries) {
    int n = arr.size();
    vector<vector<int> > dp(32, vector<int>(n, 0));
    for (int i = 0; i < n; i++) {
       dp[0][i] = (arr[i] && ((arr[i] & (arr[i]-1)) == 0));
    }
    for (int k = 1; k < 32; k++) {
        for (int i = 0; i + (1 << k) - 1 < n; i++) {
            dp[k][i] = dp[k-1][i] + dp[k-1][i+(1<<(k-1))];
            if (dp[k-1][i] == (1 << (k-1))) {
                dp[k][i] += dp[k-1][i+(1<<(k-1))];
            }
        }
    }
    vector<int> res;
    for (const auto& q : queries) {
        int L = q[0], R = q[1];
        int count = dp[log2(R-L+1)][L];
        if (L > 0) {
            count -= dp[log2(R-L+1)][L-1];
        }
        res.push_back(count);
    }
    return res;
}