八岁小孩的大o ?

我在问更多关于这对我的代码意味着什么。我能从数学上理解这些概念,只是很难理解它们在概念上的含义。例如,如果有人要对一个数据结构执行O(1)操作,我知道它必须执行的操作数量不会增长,因为有更多的项。O(n)操作意味着您将对每个元素执行一组操作。有人能帮我填一下吗?

  • 比如O(n²)的运算会怎样?
  • 如果一个操作是O(nlog (n))这是什么意思?
  • 有人必须吸可卡因才能写出O(x!)吗?
41855 次浏览

其中很多都很容易用非编程的东西来演示,比如洗牌。

对一副牌进行排序通过遍历整副牌找到黑桃a,然后遍历整副牌找到黑桃2,以此类推最坏情况是n^2,如果这副牌已经倒着排序了。你看了52张牌52次。

一般来说,真正糟糕的算法不一定是故意的,它们通常是对其他东西的误用,比如在同一集合上线性重复的另一个方法中调用一个线性方法。

不,O(n)算法并不意味着它将对每个元素执行操作。大o符号给了你一种方法来谈论你的算法的“速度”独立于你的实际机器。

O(n)表示算法花费的时间随着输入的增加而线性增长。O(n²)意味着你的算法花费的时间是你输入的平方。等等。

一种思考的方式是:

O(N²)意味着对于每个元素,你都要对其他元素做一些事情,比如比较它们。冒泡排序就是一个例子。

O(N log N)意味着对于每个元素,你只需要看log N个元素。这通常是因为你知道一些元素,可以让你做出有效的选择。最有效的排序就是一个例子,比如归并排序。

O(N!)表示对N个元素的所有可能排列进行处理。旅行推销员就是一个例子,那里有N!访问节点的方法,暴力解决方案是查看每一种可能的排列的总代价,以找到最优的一个。

你可能会发现把它形象化很有用:

Big O Analysis

同样,在呆呆的/计算lnx尺度上,N 1/2, N, N 2函数看起来都像直线,而在呆呆的/ X尺度上,2n, en, 10n是直线,而n !是线性的(看起来像N log N)。

Log (n)表示对数增长。分治算法就是一个例子。如果你在一个数组中有1000个排序的数字(例如3、10、34、244、1203…)想要在列表中搜索一个数字(找到它的位置),可以从检查索引500处的数字值开始。如果比你想要的低,跳到750。如果比你想要的高,跳到250。然后重复这个过程,直到找到值(和键)。每次我们跳过一半的搜索空间时,我们可以剔除测试许多其他值,因为我们知道数字3004不可能超过数字5000(记住,这是一个排序列表)。

N log(N)表示N * log(N)

要理解O(n log n),请记住log n意味着log-base-2 (n)。然后看看每一部分:

O(n)是,当你对集合中的每一项进行操作时。

O(log n)是指操作的次数与取2的指数相同,以得到项目的数量。例如,二分搜索必须将集合切成log n的一半。

O(nlogn)是一个组合——你在对集合中的每一项进行二分搜索。高效的排序通常是对每个项目进行一次循环,并在每个循环中进行良好的搜索,以找到放置相关项目或组的正确位置。因此是n * log n。

big - o符号对代码的重要意义在于,当它所操作的“事物”数量增加一倍时,它将如何扩展。这里有一个具体的例子:

Big-O       |  computations for 10 things |  computations for 100 things
----------------------------------------------------------------------
O(1)        |   1                         |     1
O(log(n))   |   3                         |     7
O(n)        |  10                         |   100
O(n log(n)) |  30                         |   700
O(n^2)      | 100                         | 10000

快速排序是O(nlog (n))而冒泡排序是O(n²)当排序10个东西时,快速排序比冒泡排序快3倍。但当对100个东西进行排序时,速度要快14倍!显然,选择最快的算法很重要。当您访问具有数百万行的数据库时,这可能意味着您的查询在0.2秒内执行,而不是花费数小时。

另一件需要考虑的事情是,糟糕的算法是摩尔定律无法帮助的事情。例如,如果你有一个O(n^3)的科学计算,它一天可以计算100个东西,处理器速度翻倍一天只能计算125个东西。然而,计算到O(n²),你每天要做1000件事情。

< em >澄清: 实际上,Big-O并没有说不同算法在同一特定大小点上的性能比较,而是说同一算法在不同大小点上的性能比较:

                 computations     computations       computations
Big-O       |   for 10 things |  for 100 things |  for 1000 things
----------------------------------------------------------------------
O(1)        |        1        |        1        |         1
O(log(n))   |        1        |        3        |         7
O(n)        |        1        |       10        |       100
O(n log(n)) |        1        |       33        |       664
O(n^2)      |        1        |      100        |     10000

这可能太数学化了,但这是我的尝试。(我是数学家。)

如果某个东西是O(f(n)),那么它在n元素上的运行时间将等于一个 f(n) + B(以时钟周期或CPU操作为单位)。理解这些常量一个B是关键,它们来自特定的实现。B本质上代表了你的操作的“常量开销”,例如你所做的一些预处理不依赖于集合的大小。一个表示实际项目处理算法的速度。

不过,关键是你使用大O符号来计算某物的规模有多大。所以这些常量其实并不重要:如果你试图弄清楚如何从10项扩展到10000项,谁会关心开销常量B呢?类似地,其他问题(见下文)肯定会超过乘法常数一个的重要性。

所以真正的方法是f(n)。如果fn时完全不增长,例如f(n) = 1,那么你的运行时间将始终是一个 + B。如果fn呈线性增长,即f(n) = n,那么运行时间将尽可能地扩展——如果用户为10个元素等待10ns,则他们将为10000个元素等待10000ns(忽略附加常数)。但如果它增长得更快,比如nn4,那么你就有麻烦了;当你获得更大的集合时,事情将开始变得太慢。f(n) = n log(n)是一个很好的折衷,通常:你的操作不能简单到给出线性缩放,但你已经设法减少了一些东西,这样它的缩放比f(n) = nn4要好得多。

实际上,这里有一些很好的例子:

  • O(1):从数组中检索元素。我们知道它在内存中的确切位置,所以我们去取它。收集的物品是10件还是10000件并不重要;它仍然在索引3处,所以我们跳转到内存中的位置3。
  • O(n):从链表中检索元素。这里,一个 = 0.5,因为平均来说,你必须遍历链表的1/2才能找到你要找的元素。
  • O(n2):各种“愚蠢的”排序算法。因为通常他们的策略是,对于每个元素(n),你要查看所有其他元素(因此乘以另一个n,得到n2),然后将自己定位在正确的位置。
  • O(n log(n)):各种“智能”排序算法。事实证明,你只需要查看1010-element集合中的10个元素,就可以智能地对自己相对于集合中的每一个人 else进行排序。因为所有其他人都是,将查看10个元素,并且紧急行为被精心安排,以便这足以产生一个排序的列表。
  • O(n!):一个“尝试一切”的算法,因为存在(成比例)n!n元素的可能组合可以解决给定的问题。所以它只是循环遍历所有这样的组合,尝试它们,然后在成功时停止。

我喜欢don neufeld的答案,但我想我可以加上O(nlog n)

使用简单分治策略的算法可能是O(log n)最简单的例子是在排序列表中查找某个东西。你不需要从头开始扫描。你走到中间,你决定是向后走还是向前走,跳到中途,直到你找到你要找的东西。

如果您查看快速排序或归并排序算法,您将看到它们都采用将列表分成两半,对每一半排序(使用相同的算法,递归地),然后重新组合两半的方法。这种递归分治策略将是O(nlogn)。

如果你仔细想想,你会发现快速排序对整个n项进行O(n)分区算法,然后对n/2项进行O(n)分区两次,然后对n/4项进行4次,等等……直到在1个项目上有n个分区(这是退化的)。将n分成两半得到1的次数大约是log n,每一步是O(n),所以递归分治是O(n log n)。归并排序则相反,从1个项目的n次重组开始,以n个项目的1次重组结束,其中两个排序列表的重组为O(n)。

至于抽大麻写一个O(n!)算法,除非你别无选择。上面提到的旅行推销员问题被认为是这样一个问题。

大多数Jon Bentley的书(例如编程的珍珠)以一种非常实用的方式涵盖了这些东西。他给出的这个演讲包括一个这样的快速排序分析。

虽然与问题不完全相关,Knuth想出了一个有趣的想法:在高中微积分课上教大o符号,尽管我觉得这个想法相当古怪。

好吧,这里有一些非常好的答案,但几乎所有的答案似乎都犯了同样的错误,这是一个普遍的常见用法。

非正式地,我们写f(n) = O(g(n))如果,直到一个比例因子,并且对于所有n大于某个n0, g(n)比f(n)是更大的。也就是说,f(n) 增长速度不会更快比,或从上面开始比,g(n)。这并没有告诉我们f(n)增长有多快,除了它保证不会比g(n)差。

一个具体的例子:n = O(2^n)我们都知道n的增长速度比2^n慢得多,所以我们可以说它的上界是指数函数。在n和2^n之间有很大的空间,所以它不是一个非常的边界,但它仍然是一个合法的边界。

为什么我们(计算机科学家)使用边界而不是精确?因为a)边界通常更容易证明,b)它为我们提供了一种表达算法属性的简便方法。如果我说我的新算法是O(n.log n),这意味着在最坏的情况下,它的运行时间将在n个输入上以n.log n为界,对于足够大的n(尽管请参阅下面我的评论,当我可能不是指最坏情况时)。

如果相反,我们想说一个函数的增长速度与其他函数一样快,我们使用θ来说明这一点(我将写T(f(n)),以markdown表示\Theta (f(n)))。T(g(n))是上面和下面以g(n)为界的简称,同样,直到一个比例因子且渐近。

这是f (n) = T (g (n)) & lt; f (n) = = > O (g (n))和g (n) = O (f (n))。在我们的例子中,我们可以看到n != T(2^n)因为2^n != O(n)。

为什么要担心这个呢?因为在你的问题中,你写了“一个人必须吸可卡因才能写出一个O(x!)?”答案是否定的——因为基本上你写的所有东西都会以阶乘函数为界。快速排序的运行时间是O(n!) -这不是一个严格的界限。

这里还有另一个微妙的维度。通常情况下,当我们使用O(g(n))符号时,我们谈论的是最坏情况输入,因此我们是在做一个复合语句:在最坏的情况下,运行时间不会比花费g(n)步的算法差,同样是模缩放,并且足够大的n。但有时我们想讨论平均甚至最好的情况的运行时间。

香草快速排序就是一个很好的例子。在最坏的情况下是T(n²)(实际上至少需要n²步,但不会多很多),但在平均情况下是T(n.log n),也就是说期望的步数与n.log n成正比。在最好的情况下也是T(n.log n) -但你可以改进它,例如,检查数组是否已经排序在哪种情况下,最佳运行时间将是T(n)。

这与你关于这些界限的实际实现的问题有什么关系?不幸的是,O()表示法隐藏了实际实现必须处理的常量。因此,尽管我们可以说,例如,对于T(n^2)操作,我们必须访问每一对可能的元素,我们不知道我们要访问它们多少次(除了它不是n的函数),所以我们可能要访问每一对10次,或10^10次,而T(n^2)声明没有区别。低阶函数也被隐藏了——我们可能需要访问每对元素一次,每个单独的元素100次,因为n²+ 100n = T(n²)。O()符号背后的思想是,对于足够大的n,这根本无关紧要,因为n²比100n大得多,以至于我们甚至没有注意到100n对运行时间的影响。然而,我们经常处理“足够小”的n,以至于常数等因素会产生真正的、显著的差异。

例如,快速排序(平均成本T(n.log n))和堆排序(平均成本T(n.log n))都是具有相同平均成本的排序算法——但快速排序通常比堆排序快得多。这是因为堆排序比快速排序对每个元素做了更多的比较。

这并不是说O()符号是无用的,只是不精确。对于小n来说,这是一个相当钝的工具。

(作为本文的最后一个注意事项,请记住O()表示法只是描述任何函数的增长——它不一定是时间,它可以是内存、分布式系统中交换的消息或并行算法所需的cpu数量。)

只是为了回应我上面帖子的一些评论:

Domenic -我在这个网站上,我关心。不是为了卖弄学问,而是因为我们——作为程序员——通常关心精度。不正确地使用O()表示法会使它变得毫无意义;根据这里的约定,我们也可以说某项花费了n²单位的时间,而不是O(n²)使用O()不会增加任何内容。这不仅仅是我所说的常用用法和数学精度之间的一个小差异,而是它有意义和没有意义之间的差异。

我知道很多很多优秀的程序员都准确地使用这些术语。说“哦,我们是程序员,所以我们不在乎”会降低整个企业的成本。

交谈 -嗯,不太好,尽管我接受你的观点。对于任意大的n,它不是O(1)这是O()的定义。它只是表明O()对于有界n的适用性有限,在这里我们更愿意讨论所走的步数,而不是这个数字的界限。

堂。neufeld的答案非常好,但我可能会分两部分解释它:首先,大多数算法都属于O()的粗略层次结构。然后,你可以看看每一个,得出那个时间复杂度的典型的算法是做什么的草图。

出于实际目的,似乎唯一重要的O()是:

  • O (1)“常数时间”——所需的时间与输入的大小无关。作为一个粗略的类别,我将在这里包括哈希查找和联合查找等算法,尽管它们实际上都不是O(1)。
  • O (log (n))“对数”——输入越大,速度越慢,但一旦输入变得相当大,它的变化就不会大到让人担心的程度。如果运行时可以接受合理大小的数据,那么您可以用任意多的额外数据来填充它,这仍然是可以的。
  • O (n)“线性”-输入越多,花费的时间就越长,在一个平衡的权衡中。三倍的输入大小将花费大约三倍的时间。
  • O (n log (n))“比二次元更好”——增加输入大小会带来伤害,但仍然是可控的。算法可能还不错,只是潜在的问题比那些可以在线性时间内解决的问题更难(决策相对于输入数据的本地化程度较低)。如果你的输入大小越来越大,不要认为你可以在不改变架构的情况下处理两倍的大小(例如将事情转移到隔夜批量计算,或者不按帧处理)。不过,如果输入大小增加一点也没关系;只是要注意倍数。
  • O (n ^ 2)二次函数,它只适用于你输入的一定大小,所以要注意它能达到多大。此外,你的算法可能很糟糕——仔细想想是否有O(n log(n))算法可以满足你的需求。一旦你来到这里,就会非常感激我们拥有的这些神奇的硬件。不久以前,你正在做的事情无论从什么实际角度来说都是不可能的。
  • O (n ^ 3)"立方"和O(n²)在性质上差别不大。同样的评论也适用,甚至更适用。有一个更聪明的算法很有可能将这个时间缩短到更小的时间,例如O(n²log(n))或O(n^2.8…),但话说回来,这很有可能不值得这么麻烦。(您的实际输入大小已经受到限制,因此更聪明的算法可能需要的常数因子可能会淹没它们在实际情况下的优势。而且,思考是缓慢的;总的来说,让电脑来咀嚼可以节省你的时间。)
  • O (2 ^ n)“指数型”——这个问题要么根本难以计算,要么你就是个白痴。这些问题都有其显而易见的特点。您的输入大小被限制在一个相当具体的硬限制。你很快就会知道你是否符合这个限制。

就是这样。还有很多其他的可能性在这些之间(或大于O(2^n)),但它们在实践中不经常发生,它们与这些中的任何一个在性质上没有太大的不同。三次算法已经有点牵强了;我之所以把它们包括进来,是因为我经常遇到它们,值得一提(例如矩阵乘法)。

这类算法到底发生了什么?我认为你有一个很好的开始,尽管有很多例子不符合这些特征。但对于上述情况,我认为通常是这样的:

  • O(1) -您只查看输入数据的大部分固定大小的块,可能没有一个。例如:排序列表的最大值。
    • 或者你的输入大小是有限的。示例:两个数的加法。(注意N个数字的相加是线性时间。)
    • 李< / ul > < / >
    • O(log n) -输入的每个元素都足以忽略其余输入的很大一部分。例如:当你在二分搜索中查看一个数组元素时,它的值告诉你可以忽略数组的“一半”而不查看任何数组。或者类似地,您所查看的元素为您提供了剩余输入的一部分的足够的摘要,因此您不需要查看它。
      • 二分之一并没有什么特别之处——如果你在每一步中只能忽略10%的输入,它仍然是对数。
      • 李< / ul > < / >
      • O(n) -对每个输入元素做固定量的工作。(详见下文。)
      • O(nlog (n)) -有一些变体。
        • 你可以将输入分成两堆(不超过线性时间),在每一堆上独立地解决问题,然后将两堆组合起来形成最终的解。两堆的独立性是关键。示例:经典递归归并排序。
        • 每次对数据的线性时间传递都会让你得到一半的解决方案。例如:快速排序,如果你考虑在每个分区步骤中每个元素到其最终排序位置的最大距离(是的,我知道它实际上是O(n²),因为简并枢轴选择。但实际上,它属于我的O(nlog (n))类别
        • 李< / ul > < / >
        • O(n²)-你必须查看每一对输入元素。
          • 或者你不知道,但你认为你知道,而且你用了错误的算法。
          • 李< / ul > < / >
          • O(n^3) -嗯…我对这些没有一个简单的描述。它可能是:
            • 矩阵相乘
            • 你要看每一对输入,但是你要做的操作需要再看一遍所有输入
            • 输入的整个图形结构都是相关的
            • 李< / ul > < / >
            • O(2^n) -你需要考虑输入的每个可能子集。

            这些都不严谨。尤其是线性时间算法(O(n)):我可以举出很多例子,你必须看所有的输入,然后是一半,然后是一半,等等。或者反过来——将输入对折叠在一起,然后对输出进行递归。这些不符合上面的描述,因为你不是只看一次每个输入,但它仍然是线性时间。不过,在99.2%的情况下,线性时间意味着只查看一次每个输入。

我是这样想的,你有一个任务,要清理一个由坏人V引起的问题,他选择了N,你必须估计出当他增加N时,你需要多长时间来完成你的问题。

O(1) ->增加N并没有什么不同

O(log(N)) ->每次V翻倍N,你必须花费额外的时间T来完成任务。V又翻倍了N,你花了同样多的钱。

O(N) -> V N每翻一倍,花费的时间就翻一倍。

O(N²)- V N每翻一倍,花费的时间就增加4倍。(这不公平!!)

O(nlog (N)) -, V每翻一倍N,你就花两倍的时间,再多一点。

这些是算法的边界;计算机科学家想要描述大n值需要多长时间(当你分解密码学中使用的数字时,这很重要——如果计算机速度提高了10倍,你需要多使用多少位才能确保它们仍然需要100年而不是1年才能破解你的加密?)

有些界限可能有奇怪的表达式,如果它对涉及的人有影响的话。我在Knuth的《计算机编程艺术》中见过类似于O(nlog (N) log(log(N))的算法。(我一时想不起是哪一个了)

有一件事由于某种原因还没有被提及:

当你看到像O(2^n)或O(n^3)这样的算法时,这通常意味着你将不得不接受一个不完美的问题答案,以获得可接受的性能。

在处理优化问题时,像这样的正确解决方案很常见。在合理的时间内给出一个近乎正确的答案,总比在机器腐烂成灰尘很久之后才给出一个正确答案要好。

以国际象棋为例:我不知道正确的解决方案是什么,但它可能是O(n^50)或更糟。从理论上讲,任何计算机都不可能真正计算出正确答案——即使你用宇宙中的每个粒子作为计算元素,在宇宙生命周期内尽可能短的时间内执行一项操作,你仍然会剩下很多零。(量子计算机能否解决这个问题是另一回事。)

把它想象成垂直堆叠乐高积木(n),然后跳过它们。

O(1)表示在每一步,你什么都不做。高度保持不变。

O(n)表示在每一步,你堆叠c块,其中c1是常数。

O(n²)表示在每一步,你堆叠c2 x n个块,其中c2是一个常数,n是堆叠块的数量。

O(nlogn)表示在每一步,你堆叠c3 x n x logn个块,其中c3是一个常数,n是堆叠块的数量。

告诉你8年前的log(n)意味着你必须把一个长度为nlog的东西切成两半的次数,让它变成大小为n=1:p

O(nlogn)通常是排序 O(n²)通常比较所有

的元素对
  • 有人必须吸可卡因才能写出O(x!)吗?

不用,用Prolog就行。如果您在Prolog中编写排序算法,只需描述每个元素都应该比前一个元素大,并让回溯为您进行排序,那么它将是O(x!)也称为“排列排序”。

Big-O背后的“直觉

想象一下,当x趋于无穷时,x上的两个函数f(x)和g(x)之间的“竞争”。

现在,如果从某一点开始(某个x点),一个函数的值总是比另一个高,那么我们称这个函数比另一个“快”。

例如,对于每x > 100,你看到f(x) > g(x),那么f(x)比g(x)“快”。

在这种情况下,我们可以说g(x) = O(f(x))F (x)对g(x)提出了某种“速度限制”,因为最终它超过了它,并将其永远甩在后面。

这并不完全是大0符号的定义,它还指出,对于某个常数C, f(x)只需要大于C*g(x)(这只是另一种说法,你不能通过将g(x)乘以一个常数因子来帮助g(x)赢得竞争- f(x)最终总是会赢)。正式的定义也使用绝对值。但我希望我能让它更直观。

假设你有一台可以解决一定规模问题的计算机。现在想象一下,我们可以将性能提高几倍。每加倍一次,我们能解决多大的问题?

如果我们能解决一个两倍大的问题,那就是O(n)

如果我们有一个非1的乘数,那就是某种多项式复杂度。例如,如果每加倍一次,问题的规模就会增加约40%,即O(n²),而约30%则是O(n³)。

如果我们只是增加问题的规模,它是指数级的,甚至更糟。例如,如果每翻一倍意味着我们可以解决一个大1的问题,它就是O(2^n)。(这就是为什么使用合理大小的密钥实际上不可能强制使用密码密钥:128位密钥需要的处理量大约是64位密钥的16万亿倍。)

我是这样向我那些不懂技术的朋友描述的:

考虑多位数加法。很好的老式铅笔和纸的补充。就是你7-8岁时学的那种。给定两个三位数或四位数,你很容易就能求出它们加起来是多少。

如果我给你两个100位的数字,然后问你它们加起来是多少,即使你必须使用铅笔和纸,计算出来也会非常简单。一个聪明的孩子可以在几分钟内做这样的加法。这只需要大约100次操作。

现在,考虑多位数乘法。你可能在八九岁的时候就学会了。你(希望)做了很多重复的练习来学习它背后的机制。

现在,想象我给了你两个相同的100位数然后让你把它们相乘。这将是一个非常,困难的任务,一些事情会花你几个小时去做——而且你不太可能不出错。原因是这个版本的乘法是O(n²);下面数字的每个数字都要乘以上面数字的每个数字,总共剩下大约n^2个运算。在100位数的情况下,就是10000次乘法。

还记得乌龟和兔子的寓言吗?

从长远来看,乌龟赢了,但从短期来看,兔子赢了。

这就像O(logN)(乌龟)vs O(N)(野兔)。

如果两种方法的大o值不同,那么它们中的一种会在N的水平上获胜,但大o值没有说明N的大小。

我试图通过在C#JavaScript中给出简单的代码示例来解释。

c#

对于List<int> numbers = new List<int> {1,2,3,4,5,6,7,12,543,7};

O(1)看起来像

return numbers.First();

O(n)看起来像

int result = 0;
foreach (int num in numbers)
{
result += num;
}
return result;

O(nlog (n))是这样的

int result = 0;
foreach (int num in numbers)
{
int index = numbers.Count - 1;
while (index > 1)
{
// yeah, stupid, but couldn't come up with something more useful :-(
result += numbers[index];
index /= 2;
}
}
return result;

O(n2)看起来像

int result = 0;
foreach (int outerNum in numbers)
{
foreach (int innerNum in numbers)
{
result += outerNum * innerNum;
}
}
return result;

O(n!)看起来,嗯,太累了,想不出任何简单的东西。
但我希望你能明白大意?< / p >


JavaScript

对于const numbers = [ 1, 2, 3, 4, 5, 6, 7, 12, 543, 7 ];

O(1)看起来像

numbers[0];

O(n)看起来像

let result = 0;
for (num of numbers){
result += num;
}

O(nlog (n))是这样的

let result = 0;
for (num of numbers){


let index = numbers.length - 1;
while (index > 1){
// yeah, stupid, but couldn't come up with something more useful :-(
result += numbers[index];
index = Math.floor(index/2)
}
}

O(n2)看起来像

let result = 0;
for (outerNum of numbers){
for (innerNum of numbers){
result += outerNum * innerNum;
}
}

为了对被问到的问题保持真诚,我会用回答8岁孩子的方式来回答这个问题

假设一个卖冰淇淋的小贩准备了许多不同形状的冰淇淋(比方说N个),以有序的方式排列。 你想吃中间的冰淇淋

情况1:-只有你吃完了所有比它小的冰淇淋,你才能吃冰淇淋 你将不得不吃掉一半准备好的冰淇淋(输入)。答案直接取决于输入的大小 解的阶为o(N)

情况2:—你可以直接吃中间的冰淇淋

解是O(1)

情况3:只有当你吃完所有比它小的冰淇淋时,你才能吃冰淇淋,而且每次你吃冰淇淋时,你都允许另一个孩子(每次都是新孩子)吃掉他所有的冰淇淋 总时间为N + N + N.......(N/2)次 溶液为O(N2)

我会试着为一个真正的八岁男孩写一个解释,除了专业术语和数学概念。

比如O(n^2)操作到底会做什么?

如果你在一个聚会上,并且有n人在聚会上,包括你。需要多少次握手才能让每个人都和其他人握手,因为人们可能会在某个时候忘记他们握手的人是谁。

注意:这近似于产生n(n-1)的单形,它足够接近n^2

如果一个操作是O(n log(n)),这到底意味着什么?

你最喜欢的球队赢了,他们在排队,球队里有n名球员。你需要和每个玩家握手多少次,假设你要和每个玩家握手多次,多少次,玩家n的号码中有多少位数字。

注意:这将产生n * log n to the base 10

有人必须吸可卡因才能写O(x!)吗?

你是一个富二代,你的衣柜里有很多衣服,每一种衣服都有x个抽屉,抽屉一个挨着一个,第一个抽屉里有一件衣服,每个抽屉里有和左边抽屉一样多的衣服,所以你有像1帽子,2假发,…(x-1)裤子,然后x衬衫。现在,用每个抽屉里的一件物品,你能装扮出多少种风格呢?

注意:这个例子表示决策树中number of children = depth处有多少个叶结点,这是通过1 * 2 * 3 * .. * x完成的