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

查找多个元素时线性搜索的时间复杂度疑问及基准分析

线性遍历查找多个目标元素的平均比较次数分析

问题背景

对比暴力搜索与自定义搜索方法时,需估算暴力搜索的复杂度:检查指定元素是否存在于无序列表中,以包含[1..99999]的整数列表为测试样本(共99999个元素),通过线性遍历统计找到所有目标元素所需的比较次数(对应代码中search.contains(values.get(i))操作)。

基准测试结果(1000次运行)

  • 搜索1个元素:平均约50000次比较,对应期望公式$\frac{N+1}{2}$,复杂度$O(N)$,此情况已理解;
  • 搜索2个元素:平均约65000次比较,需推导对应的数学公式与计算复杂度;
  • 搜索3个元素:平均约75000次比较,需推导对应的数学公式与计算复杂度。

测试代码

public static void main(String[] args) {
    List<Integer> values = IntStream.range(1, 100_000).boxed().toList();

    List<Integer> results1 = new ArrayList<>();
    List<Integer> results2 = new ArrayList<>();
    List<Integer> results3 = new ArrayList<>();

    Set<Integer> search1 = Set.of(1);
    Set<Integer> search2 = Set.of(1, 2);
    Set<Integer> search3 = Set.of(1, 2, 3);

    for (int i = 0; i < 1000; i++) {
        results1.add(search(values, search1));
        results2.add(search(values, search2));
        results3.add(search(values, search3));
    }
    System.out.println("Search 1: " + results1.stream().mapToInt(i->i).average().getAsDouble());
    System.out.println("Search 2: " + results2.stream().mapToInt(i->i).average().getAsDouble());
    System.out.println("Search 3: " + results3.stream().mapToInt(i->i).average().getAsDouble());
}

private static int search(List<Integer> list, Set<Integer> search) {
    List<Integer> values = new ArrayList<>(list);
    Collections.shuffle(values);

    int i = 0;
    int found = 0;
    for (; i < values.size(); i++) {
        if (search.contains(values.get(i))) {
            ++found;
        }
        if (found == search.size()) {
            break;
        }
    }
    return i+1;
}

数学公式推导与复杂度分析

核心结论

对于包含$N$个元素的无序列表,查找$k$个不同目标元素时,找到所有目标所需的平均比较次数的数学公式为:
$$E(k) = \frac{k \times (N+1)}{k+1}$$

推导依据

问题本质是:在随机打乱的数组中,找到第$k$个目标元素时的遍历次数(1-based位置)的期望值。利用排列的对称性可知,$k$个目标元素在数组中的位置的期望是均匀分布的——将整个数组的位置划分为$k+1$个等期望长度的区间,因此第$m$个目标元素的期望位置为$\frac{m \times (N+1)}{k+1}$。当找到第$k$个目标元素时停止遍历,此时的平均比较次数就是第$k$个目标元素的期望位置。

验证与结果

  • 当$k=1$,$N=99999$时:$E(1)=\frac{1 \times (99999+1)}{1+1}=50000$,与测试结果完全吻合;
  • 当$k=2$,$N=99999$时:$E(2)=\frac{2 \times (99999+1)}{2+1}≈66666.67$,与测试结果的65000接近,差异源于测试样本的随机误差;
  • 当$k=3$,$N=99999$时:$E(3)=\frac{3 \times (99999+1)}{3+1}=75000$,与测试结果完全吻合。

时间复杂度

从公式可以看出,平均比较次数的主导项为$\frac{k}{k+1}N$,当$k$远小于$N$时,$\frac{k}{k+1}$趋近于1,因此时间复杂度仍为**$O(N)$**——即使查找多个目标元素,暴力遍历的渐近复杂度依然是线性的,只是常数因子随$k$增大而趋近于1。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.23 18:04:53