假设有一个巨大的阵列,只填充了几个位置。我需要找到某个位置a和位置b之间的总和,a<湾
我能比O(n)做得更好吗?如果有,怎么样?
答案 0 :(得分:0)
如果您的稀疏数组是作为一个天真的本机数组(例如int[999999]
)实现的,那么O(n/p)
时间内没有比手动迭代更快的方式(其中p
是你有硬件线程。)
如果您的稀疏数组以存储优化格式(例如页面数组或页面链接列表)存储,则最快的是O(m/p)
,其中m
是pages和p
是硬件线程的数量。
更新:
在评论中,您评论说您需要一个运行速度超过O(n)
的单线程解决方案。这是不可能的。考虑这个稀疏数组:
arr = [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0 ]
计算机无法像人眼+大脑一样“一次”“看到”数组。单线程计算机一次只能处理一个字(通常为32或64位)的数据。所有计算机都知道arr
内有一个数组,所以它开始读取它,它看到0
,然后它再次读取0
,依此类推,读取11 {{1}直到它最终遇到0
值。这是1
解决方案。
击败这个的唯一方法是使用并行化:人眼+大脑可以被认为是拥有超过5.76亿线程(人眼的90度has 576 megapixels)的机器,它“看到”我的StackOverflow中的整个数组立即发布(O(n)
)。对于计算机执行相同操作,您的程序必须具有许多线程(具有预编程的数据偏移),这些线程同时读取阵列,然后为您提供答案:
O(1)
这是获得void Main() {
// Setup the threads
volatile int total = 0;
WaitHandle ev = new WaitHandle();
Int32[] arr;
ev.Reset();
for(int i=0; i < 100; i++) {
(new Thread( delegate() {
int offset = i;
ev.WaitOne();
total += arr[offset]; // assume this is a magic thread-safe increment operation
} )).Start();
}
// Load the array
Int32[] arr = new Int32[] { /* 100 values */ };
ev.Set(); // unblock all 100 threads instantly
// assume there's a magic Thread.Join() wait here
Console.WriteLine("Total: {0}.", total);
}
时间以数学方式计算稀疏数组之和的唯一方法。
...但即使这是不可能的,因为不存在“魔术线程安全添加”操作。您可以做的最好的是O(1)
- 中间加法操作的级别(其中m
的值为m
),但它仍然非常接近Log[X](n)
。
答案 1 :(得分:0)
是的,您可以使用二进制索引树(或段树)来执行O(logN)
个查询。
https://www.topcoder.com/community/data-science/data-science-tutorials/binary-indexed-trees/ https://en.wikipedia.org/wiki/Fenwick_tree