有没有O(1 / n)算法?

时间:2009-05-25 06:15:28

标签: theory complexity-theory big-o

是否有任何O(1 / n)算法?

或其他任何小于O(1)的东西?

33 个答案:

答案 0 :(得分:300)

这个问题并不像看起来那么愚蠢。至少在理论上,当我们采用Big O notation的数学定义时,诸如 O (1 / n )之类的东西是完全合理的:

现在您可以轻松地将 g x )替换为1 / x ...很明显上面的定义仍适用于某些˚F

为了估计渐近运行时增长,这不太可行......随着输入的增长,有意义的算法无法加速。当然,您可以构建一个任意算法来实现这一点,例如:以下一个:

def get_faster(list):
    how_long = (1 / len(list)) * 100000
    sleep(how_long)

显然,这个函数在输入大小增加时花费的时间更少......至少在某些限制之前,由硬件强制执行(数字的精确度,sleep可以等待的最短时间,处理参数的时间等等。 ):这个限制将是一个恒定的下限,所以实际上上面的函数仍然有运行时 O (1)。

实际上是实际算法,其中运行时可以在输入大小增加时(至少部分地)减少。请注意,这些算法会在 O (1)下显示运行时行为。他们仍然很有趣。例如,按Horspool采用非常简单的文本搜索算法。这里,随着搜索模式的长度增加,预期的运行时间将减少(但是,草堆的长度将再次增加运行时间)。

答案 1 :(得分:129)

是。

只有一种算法具有运行时O(1 / n),即“空”算法。

对于算法为O(1 / n)意味着它以比单个指令组成的算法更少的步长渐近地执行。如果它以比所有n> 1的步骤更少的步骤执行。 n0,对于那些n,它必须完全没有指令。自检查'if n> n0'至少要花费1条指令,它必须包含所有n的指令。

总结: 唯一的算法是O(1 / n)是空算法,由 no 指令组成。

答案 2 :(得分:24)

那是不可能的。 Big-O的定义是不大于不等式:

A(n) = O(B(n))
<=>
exists constants C and n0, C > 0, n0 > 0 such that
for all n > n0, A(n) <= C * B(n)

所以B(n)实际上是最大值,因此如果它随着n的增加而减小,估计就不会改变。

答案 3 :(得分:23)

sharptooth是正确的,O(1)是最好的表现。但是,它并不意味着快速解决方案,只是一个固定的时间解决方案。

一个有趣的变体,也许真正建议的是,随着人口的增长,哪些问题会变得更容易。我可以想到1,尽管是做作和诙谐的回答:

一组中的任何两个人都有同一个生日吗?当n超过365时,返回true。虽然小于365,但这是O(n ln n)。也许不是一个很好的答案,因为问题不会慢慢变得容易,但只是变为O(1)n> 365。

答案 4 :(得分:15)

从我之前学习的大O符号开始,即使你需要一步(例如检查一个变量,做一个赋值),那就是O(1)。

注意O(1)与O(6)相同,因为“常数”无关紧要。这就是我们说O(n)与O(3n)相同的原因。

因此,如果您甚至需要一步,那就是O(1)......并且因为您的程序至少需要1步,所以算法的最小值可以是O(1)。除非我们不这样做,否则它是O(0),我想?如果我们做任何事情,那么它就是O(1),这是它可以达到的最小值。

(如果我们选择不这样做,那么它可能成为一个禅或道问题......在编程领域,O(1)仍然是最小的。)

或者这个怎​​么样:

程序员:老板,我找到了办法在O(1)时间内完成!
老板:没必要,我们今天早上破产了 程序员:哦,那就变成了O(0)。

答案 5 :(得分:8)

不,这是不可能的:

当n在1 / n中趋于无穷大时,我们最终得到1 /(inf),实际上是0。

因此,问题的大哦类别是具有大量n的O(0),但是接近具有低n的恒定时间。这是不明智的,因为唯一可以在比常数更快的时间内完成的事情是:

void nothing() {};

即使这是有争议的!

一旦你执行一个命令,你至少在O(1),所以不,我们不能有一个很大的O级(1 / n)!

答案 6 :(得分:7)

我经常使用O(1 / n)来描述随着输入变大而变小的概率 - 例如,log2(n)翻转时公平硬币出现的概率为O(1 / n)

答案 7 :(得分:7)

根本没有运行该功能(NOOP)怎么样?或使用固定值。这算了吗?

答案 8 :(得分:6)

O(1)仅表示“恒定时间”。

当您将一个早期退出添加到循环[1]时,您(以大O表示法)将O(1)算法转换为O(n),但使其更快。

技巧一般恒定时间算法是最好的,线性比指数更好,但对于少量的n,指数算法实际上可能更快。

1:假设此示例的静态列表长度

答案 9 :(得分:5)

我相信量子算法可以通过叠加“一次”进行多次计算......

我怀疑这是一个有用的答案。

答案 10 :(得分:5)

对于那些阅读此问题并希望了解对话内容的人来说,这可能有所帮助:

collect()

答案 11 :(得分:3)

很多人都有正确的答案(不)这是证明它的另一种方式:为了拥有一个功能,你必须调用该功能,你必须返回一个答案。这需要一定的时间。即使其余的处理花费更少的时间来处理更大的输入,打印答案(我们可以假设是一个单位)至少需要一个恒定的时间。

答案 12 :(得分:2)

如果存在解决方案,可以立即准备和访问它。例如,如果您知道排序查询是针对逆序,则使用LIFO数据结构。然后,在选择了适当的模型(LIFO)的情况下,数据已经被分类。

答案 13 :(得分:2)

你不能低于O(1),但是k(小于N)的O(k)是可能的。我们称他们为sublinear time algorithms。在一些问题中,次线性时间算法只能给出特定问题的近似解。但是,有时,近似解决方案很好,可能是因为数据集太大,或者计算所有数据集的计算成本太高。

答案 14 :(得分:2)

随着人口增长,哪些问题变得更容易?一个答案是像bittorrent这样的东西,其中下载速度是节点数量的反函数。与汽车相反,加载的速度越慢,像bittorrent这样的文件共享网络会加速连接的节点。

答案 15 :(得分:1)

O(1 / n)不小于O(1),它基本上意味着你拥有的数据越多,算法就越快。假设你得到一个数组并且总是填充最多10个 100 元素,如果它少于那个并且如果还有更多就什么也不做。这个当然不是O(1 / n),而是O(-n):)太糟糕的O-big表示法不允许负值。

答案 16 :(得分:1)

正如已经指出的那样,除了null函数可能的例外之外,可能没有O(1/n)函数,因为所花费的时间必须接近0。

当然,有一些算法,比如Konrad定义的算法,看起来它们至少在某种程度上应该小于O(1)

def get_faster(list):
    how_long = 1/len(list)
    sleep(how_long)

如果您想研究这些算法,您应该定义自己的渐近测量,或者您自己的时间概念。例如,在上面的算法中,我可以允许使用一定次数的“自由”操作。在上面的算法中,如果我通过排除除睡眠之外的所有时间来定义t',那么t'= 1 / n,即O(1 / n)。可能有更好的例子,因为渐近行为是微不足道的。事实上,我相信那里的某个人可以想出能给你带来不平凡结果的感官。

答案 17 :(得分:1)

其余大部分答案都将big-O解释为完全与算法的运行时间有关。但由于这个问题没有提及,我认为值得一提的是big-O在数值分析中的其他应用,即关于错误。

许多算法可以是O(h ^ p)或O(n ^ { - p}),这取决于您是否在谈论步长(h)或分割数(n)。例如,在Euler's method中,如果你知道y(0)和dy / dx(y的导数),你会找到y(h)的估计值。你的y(h)的估计值越准确越近h为0.因此,为了找到某个任意x的y(x),将0到x间隔,将其分解为n个,然后运行Euler&# 39;每个点的方法,从y(0)到y(x / n)到y(2x / n),依此类推。

因此Euler的方法是O(h)或O(1 / n)算法,其中h通常被解释为步长,n被解释为划分区间的次数。 / p>

由于floating point rounding errors,您还可以在实际数值分析应用程序中使用O(1 / h)。您创建间隔越小,某些算法的实现取消的次数就越多,有效数字的丢失就越多,因此会产生更多错误,这些错误会通过算法传播。

对于Euler的方法,如果你使用的是浮点数,请使用足够小的步数和取消,然后将一个小数字添加到一个大数字,保留大数字不变。对于通过从两个非常接近的位置处评估的函数中相互减去两个数来计算导数的算法,用(y(x + h) - y(x)/ h)逼近y&#39;(x),平滑函数y(x + h)接近y(x),导致大的取消和对具有较少有效数字的导数的估计。这将反过来传播到您需要衍生物的任何算法(例如,边界值问题)。

答案 18 :(得分:0)

在数值分析中,近似算法在近似容差中应具有亚常数渐近复杂度。

class Function
{
    public double[] ApproximateSolution(double tolerance)
    {
        // if this isn't sub-constant on the parameter, it's rather useless
    }
}

答案 19 :(得分:0)

我想小于O(1)是不可能的。算法占用的任何时间称为O(1)。但是对于O(1 / n),下面的函数如何。 (我知道此解决方案中已经提供了许多变体,但是我想它们都有一些缺陷(不是主要的,它们很好地解释了这个概念。)所以这里是一个,仅出于争论的目的:

def 1_by_n(n, C = 10):   #n could be float. C could be any positive number
  if n <= 0.0:           #If input is actually 0, infinite loop.
    while True:
      sleep(1)           #or pass
    return               #This line is not needed and is unreachable
  delta = 0.0001
  itr = delta
  while delta < C/n:
    itr += delta

因此,随着n的增加,该功能将花费越来越少的时间。此外,还可以确保如果输入实际为0,则该函数将永远返回。

有人可能会说它将受到机器精度的限制。因此,它的上限是O(1)。但是我们也可以通过输入字符串n和C来绕过它。并且对字符串进行加法和比较。想法是,有了这个,我们可以任意减小n。因此,即使我们忽略n = 0,该函数的上限也不受限制。

我还相信我们不能仅仅说运行时间是O(1 / n)。但是我们应该说O(1 + 1 / n)

答案 20 :(得分:0)

我看到一个O(1 / n)的算法无可置疑地在上限:

由于例程外部的某些东西(可能它们反映了硬件,或者甚至可能是处理器中的其他核心),您有大量输入正在发生变化。并且您必须选择随机但有效的输入。

现在,如果它没有改变,你只需要制作一个项目列表,随机选择一个并获得O(1)时间。但是,数据的动态特性排除了列表,您只需随机探测并测试探针的有效性。 (并且注意到固有地不能保证答案在返回时仍然有效。这仍然可以用于 - 例如,游戏中的单位的AI。它可以射击目标,当它是扣动扳机。)

这是无穷大的最差情况,但平均情况表现随着数据空间的增加而下降。

答案 21 :(得分:0)

这个怎么样:

void FindRandomInList(list l)
{
    while(1)
    {
        int rand = Random.next();
        if (l.contains(rand))
            return;
    }
}

随着列表大小的增加,程序的预期运行时间会减少。

答案 22 :(得分:0)

好的,我做了一些思考,也许存在一种可以遵循这种一般形式的算法:

您需要计算1000个节点图的旅行商问题,但是,您还会获得一个您无法访问的节点列表。随着不可访问节点列表变大,问题变得更容易解决。

答案 23 :(得分:-1)

我在2007年遇到了这样的疑问,很高兴看到这个帖子,我从我的reddit线程来到这个帖子 - &gt; http://www.reddit.com/r/programming/comments/d4i8t/trying_to_find_an_algorithm_with_its_complexity/

答案 24 :(得分:-1)

可以构造一个O(1 / n)的算法。一个例子是循环迭代f(n)-n次的一些倍数,其中f(n)是一些函数,其值保证大于n,并且当n接近无穷大时f(n)-n的极限是零。对于所有n,f(n)的计算也需要是常数。我不知道f(n)看起来会是什么样的或者这样的算法会有什么应用,但是在我看来这样的函数可能存在,但是得到的算法没有其他目的,只能证明算法的可能性。 O(1 / n)中。

答案 25 :(得分:-1)

我不了解算法,但在随机算法中出现了小于O(1)的复杂性。实际上,o(1)(小o)小于O(1)。这种复杂性通常出现在随机算法中。例如,正如您所说,当某个事件的概率为1 / n时,它们用o(1)表示。或者当他们想要说某些事情发生的概率很高(例如1 - 1 / n)时,他们用1 - o(1)表示它。

答案 26 :(得分:-2)

inline void O0Algorithm() {}

答案 27 :(得分:-2)

这是一个简单的O(1 / n)算法。它甚至做了一些有趣的事情!

function foo(list input) {
  int m;
  double output;

  m = (1/ input.size) * max_value;  
  output = 0;
  for (int i = 0; i < m; i++)
    output+= random(0,1);

  return output;
}

O(1 / n)是可能的,因为它描述了在增加输入大小的情况下函数输出如何变化。如果我们使用函数1 / n来描述函数执行的指令数,则不要求函数对任何输入大小采用零指令。相反,对于每个输入大小,n高于某个阈值,所需的指令数量高于正常数乘以1 / n。由于没有1 / n为0的实际数字,并且常数为正数,因此没有理由将函数限制为采用0或更少的指令。

答案 28 :(得分:-2)

没有什么比O(1)小 Big-O表示法意味着算法的最大复杂度

如果算法的运行时间为n ^ 3 + n ^ 2 + n + 5,那么它是O(n ^ 3) 在这里,较低的功率根本不重要,因为n - >与n ^ 3

相比,Inf,n ^ 2将无关紧要

同样作为n - &gt;与O(1)相比,Inf,O(1 / n)将无关紧要,因此3 + O(1 / n)将与O(1)相同,从而使O(1)成为可能的最小计算复杂度

答案 29 :(得分:-2)

Big-O表示法表示算法的最差情况,该算法与其典型运行时间不同。很容易证明O(1 / n)算法是O(1)算法。根据定义,
O(1 / n) - > T(n)<= 1 / n,对于所有n> = C> 1。 0
O(1 / n) - > T(n)<= 1 / C,因为1 / n <= 1 / C,所有n> = C O(1 / n) - > O(1),因为Big-O表示法忽略常数(即C的值无关紧要)

答案 30 :(得分:-2)

如果答案是相同的,无论输入数据如何,那么你有一个O(0)算法。

或换句话说 - 在提交输入数据之前已知答案 - 可以优化函数 - 所以O(0)

答案 31 :(得分:-3)

有子线性算法。事实上,Bayer-Moore search算法是一个很好的例子。

答案 32 :(得分:-3)

我不理解数学,但是这个概念似乎在寻找一个在添加更多输入时花费更少时间的函数?在那种情况下:

def f( *args ): 
  if len(args)<1:
    args[1] = 10

添加可选的第二个参数时,此功能更快,因为否则必须分配它。我意识到这不是一个等式,但随后wikipeadia页面说big-O也经常应用于计算系统。