是否有O(1 / n)算法?
还是其他小于O(1)的东西?
是否有O(1 / n)算法?
还是其他小于O(1)的东西?
Answers:
这个问题并不像看起来那样愚蠢。至少从理论上讲,当我们采用Big O符号的数学定义时,诸如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的非常简单的文本搜索算法。在这里,预期的运行时间将随着搜索模式长度的增加而减少(但是,增加干草堆的长度将再次增加运行时间)。
是。
恰好有一种运行时为O(1 / n)的算法,即“空”算法。
对于O(1 / n)算法来说,它比由单个指令组成的算法以更少的步长渐近执行。如果对于所有n> n0,它执行的步数少于一个步骤,则对于这些n,它必须完全不包含任何指令。由于检查“如果n> n0”花费至少1条指令,因此对于所有n,它必须不包含任何指令。
总结:唯一的算法为O(1 / n)是空算法,不包含任何指令。
Sharptooth是正确的,O(1)是可能的最佳性能。但是,这并不意味着快速的解决方案,而仅是固定时间的解决方案。
一个有趣的变体,也许是真正的建议,是随着人口的增长,问题变得更加容易。我可以想到1,尽管人为和嘲讽的答案:
一组中的两个人有相同的生日吗?当n超过365时,返回true。虽然小于365,但这是O(n ln n)。也许这不是一个很好的答案,因为问题并不会慢慢变得简单,而是在n> 365时变成O(1)。
那不可能 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)实际上是最大值,因此,如果B随着n的增加而减小,则估计值不会改变。
根据我以前对大O表示法的了解,即使您需要1个步骤(例如检查变量,执行赋值),也就是O(1)。
请注意,O(1)与O(6)相同,因为“常数”无关紧要。这就是为什么我们说O(n)与O(3n)相同。
因此,即使您只需要1步,也就是O(1)...,并且由于您的程序至少需要1步,因此算法可以执行的最小值为O(1)。除非我们不这样做,否则我认为它是O(0)?如果我们什么都不做,那就是O(1),这是它可以经过的最小值。
(如果我们选择不这样做,那么它可能会成为Zen或Tao问题……在编程领域,O(1)仍然是最小值)。
还是这样:
程序员:老板,我找到了一种在O(1)时间内做到的方法!
老板:没必要这样做,我们今天早上破产了。
程序员:哦,那变成O(0)。
根本不运行该功能(NOOP)怎么办?或使用固定值。这算吗?
我经常使用O(1 / n)来描述随着输入变大而变小的概率-例如,公平硬币在log2(n)翻转时出现尾巴的概率为O(1 / n)。
对于阅读此问题并想了解对话内容的任何人,这可能会有所帮助:
| |constant |logarithmic |linear| N-log-N |quadratic| cubic | exponential |
| n | O(1) | O(log n) | O(n) |O(n log n)| O(n^2) | O(n^3) | O(2^n) |
| 1 | 1 | 1 | 1| 1| 1| 1 | 2 |
| 2 | 1 | 1 | 2| 2| 4| 8 | 4 |
| 4 | 1 | 2 | 4| 8| 16| 64 | 16 |
| 8 | 1 | 3 | 8| 24| 64| 512 | 256 |
| 16 | 1 | 4 | 16| 64| 256| 4,096 | 65536 |
| 32 | 1 | 5 | 32| 160| 1,024| 32,768 | 4,294,967,296 |
| 64 | 1 | 6 | 64| 384| 4,069| 262,144 | 1.8 x 10^19 |
我相信量子算法可以通过叠加“一次”进行多种计算。
我怀疑这是一个有用的答案。
许多人都有正确的答案(否)这是另一种证明方法:要拥有一个函数,您必须调用该函数,并且必须返回一个答案。这需要一定的恒定时间。即使对于较大的输入,其余处理花费的时间更少,打印出答案(我们可以假定为单个位)至少需要恒定的时间。
您不能低于O(1),但是可以选择其中k小于N的O(k)。我们称它们为亚线性时间算法。在某些问题中,亚线性时间算法只能给出特定问题的近似解。但是,有时,近似解就很好了,这可能是因为数据集太大,或者计算所有数据都太昂贵了。
那这个呢:
void FindRandomInList(list l)
{
while(1)
{
int rand = Random.next();
if (l.contains(rand))
return;
}
}
随着列表大小的增加,程序的预期运行时间会减少。
constains
O(1)
O(1 / n)不小于O(1),这基本上意味着您拥有的数据越多,算法就越快。假设您得到一个数组,并且如果该数组少于该数组,则始终最多填充10 100个元素;如果有更多数组,则不执行任何操作。当然这不是O(1 / n),而是O(-n):)太差的O-big表示法不允许负值。
正如已经指出的那样,除了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)。可能有更好的例子,因为渐近行为是微不足道的。实际上,我确信外面有人会产生非凡的感官。
其余大多数答案都将big-O解释为仅与算法的运行时间有关。但是由于问题没有提及,我认为值得一提的是big-O在数值分析中的其他应用,这与错误有关。
许多算法可以是O(h ^ p)或O(n ^ {-p}),具体取决于您是在讨论步长(h)还是除法数(n)。例如,在Euler方法中,假设您知道y(0)和dy / dx(y的导数),则寻找y(h)的估计。您对y(h)的估计越接近h,它的精度就越高。因此,为了找到某个任意x的y(x),将0到x的间隔取为0,将其拆分为n个部分,然后运行Euler方法在每个点上,从y(0)到y(x / n)到y(2x / n),依此类推。
因此,欧拉的方法就是O(h)或O(1 / n)算法,其中h通常被解释为步长,n被解释为除以间隔的次数。
由于浮点舍入误差,在实际数值分析应用程序中也可以使用O(1 / h)。间隔越小,执行某些算法所产生的抵消就越多,有效位数的损失也就越大,因此通过算法传播的错误也就越多。
对于欧拉方法,如果您使用浮点数,请使用足够小的步长并进行抵消,然后将一个小数加到一个大数上,而使大数保持不变。对于通过在两个非常接近的位置求值的函数彼此相减两个数来计算导数的算法,在平滑函数y中用(y(x + h)-y(x)/ h)近似y'(x) (x + h)接近y(x),从而导致较大的抵消,并且用较少的有效数字来估计导数。反过来,这将传播到您需要导数的任何算法(例如,边值问题)。
好的,我对此进行了一些思考,也许存在一种可以遵循以下一般形式的算法:
您需要计算1000个节点图的旅行商问题,但是,您还会得到一个无法访问的节点列表。随着不可见节点列表的增加,该问题变得更容易解决。
我看到一个公认的上限是O(1 / n)的算法:
您有大量的输入,这些输入由于例程外部的某些因素而改变(也许它们反映了硬件,或者甚至可能是处理器中执行此操作的其他内核。),您必须选择一个随机但有效的输入。
现在,如果没有更改,您只需列出项目清单,随机选择一个即可获得O(1)时间。但是,数据的动态性质使您无法创建列表,您只需要随机进行探测并测试探测的有效性即可。(请注意,从本质上讲,不能保证返回答案时该答案仍然有效。这仍然可以使用-例如,游戏中某个单元的AI。它可能会在目标瞄准时掉落的目标射击拉动扳机。)
这具有最坏情况下的无穷大性能,但平均情况下的性能随着数据空间的填充而下降。
在数值分析中,逼近算法的逼近容限应具有亚恒定的渐近复杂度。
class Function
{
public double[] ApproximateSolution(double tolerance)
{
// if this isn't sub-constant on the parameter, it's rather useless
}
}
我想小于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)
可以构造一个O(1 / n)的算法。一个例子是一个循环,迭代f(n)-n的倍数,其中f(n)是某个函数,其值保证大于n,并且当n接近无穷大时f(n)-n的极限为零。对于所有n,f(n)的计算也需要保持不变。我不立即知道f(n)会是什么样子,或者这种算法有什么应用,但是我认为可以存在这样的功能,但是最终的算法除了证明用O(1 / n)。
Big-O表示一种算法的最坏情况,它与典型运行时间不同。证明O(1 / n)算法是O(1)算法很简单。根据定义,
对于所有n> = C> 0
O(1 / n)-> T(n)<= 1 / C,O(1 / n)-> T(n)<= 1 / n对于所有n> = C
O(1 / n)-> O(1),1 / n <= 1 / C ,因为Big-O表示忽略常量(即C的值无关紧要)
hashtable-contains
,可以将其表示为O(1),最坏的情况可以非常精确地表示为Theta(n)!欧米茄(Omega)和塞塔(Theta)可能只是用来表示其他界限,但要再说一遍:它们与一般情况或最佳情况无关。
inline void O0Algorithm() {}
这是一个简单的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个或更少的指令。