You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何高效统计数组中被标记为True的元素数?优化O(N²)算法

优化布尔数组标记统计的时间复杂度问题

现有一个大小为N、初始化为False的布尔数组,以及一组互不相同的正整数集合S。对于S中的每个元素e,需将数组1索引下能被e整除的位置设为True。例如当N=6、S={2,3}时,结果数组为{0,1,1,1,0,1}(注:数组采用0索引存储,对应1索引的位置1到6)。

现有C++实现代码如下:

bool arr[N]{};
for(int e : S) {
    for(int i = e-1; i < N; i += e) {
        arr[i] = true;
    }
}

该实现可行但效率不足,当S的元素数量可达N时,时间复杂度为O(N²)。由于仅需统计最终数组中True元素的数量,请问是否存在更快的实现方式,时间复杂度最好为O(NlogN)或更优?


优化方案:基于筛法的去重标记统计

有更高效的实现方式,核心是避免对同一位置重复标记,借鉴埃拉托斯特尼筛法的思路,先筛选出S中无需重复处理的核心元素,再进行统计。

具体步骤

  • 第一步:标记S中的元素
    创建大小为N+1的辅助数组is_in_S,初始化为False,遍历集合S,将is_in_S[e]设为True(仅处理≤N的元素,大于N的元素无对应数组位置,可直接忽略)。
  • 第二步:筛除冗余元素
    从1到N遍历每个数x,若is_in_S[x]为True,则将x的所有倍数(2x、3x…≤N)对应的is_in_S设为False。这些倍数属于冗余元素,因为它们的标记范围已被更小的x覆盖,无需单独处理。
  • 第三步:统计有效标记数量
    创建大小为N的marked数组(初始为False),遍历所有is_in_S[x]为True的x,从x-1(对应1索引的x)开始,以x为步长遍历数组,将未标记的位置设为True并计数。

C++代码示例

int count_true(int N, const vector<int>& S) {
    vector<bool> is_in_S(N + 1, false);
    for (int e : S) {
        if (e <= N) {
            is_in_S[e] = true;
        }
    }

    // 筛除S中为其他元素倍数的冗余元素
    for (int x = 1; x <= N; ++x) {
        if (is_in_S[x]) {
            for (int multiple = 2 * x; multiple <= N; multiple += x) {
                is_in_S[multiple] = false;
            }
        }
    }

    vector<bool> marked(N, false);
    int count = 0;
    for (int x = 1; x <= N; ++x) {
        if (is_in_S[x]) {
            for (int i = x - 1; i < N; i += x) {
                if (!marked[i]) {
                    marked[i] = true;
                    count++;
                }
            }
        }
    }
    return count;
}

复杂度分析

该实现的时间复杂度为O(NlogN):第一步遍历S为O(|S|),第二步筛除冗余元素和第三步标记统计的复杂度均与埃氏筛一致,为O(NlogN),整体由O(NlogN)主导,远优于原实现的O(N²)。

可选优化:数学法直接计算

若无需构建数组,可基于容斥原理直接计算:先得到经过筛选后的核心元素集合T,计算1到N中至少是T中一个元素倍数的数的个数——对每个元素x计算N/x,减去两两公倍数的个数,加上三三公倍数的个数,以此类推。但当T的元素较多时,容斥的复杂度会指数上升,因此筛法标记的方式更通用。

内容的提问来源于stack exchange,提问作者Mystical

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.06 08:03:02