什么会导致算法具有 O(log n) 复杂度?

2023-11-22

我对大 O 的了解是有限的,当对数项出现在方程中时,它让我更加困惑。

有人可以用简单的语言向我解释一下什么是O(log n)算法是?对数从何而来?

当我试图解决这个期中练习题时,特别出现了这个问题:

令 X(1..n) 和 Y(1..n) 包含两个整数列表,每个列表均按非降序排序。给出一个 O(log n) 时间算法来查找所有 2n 个组合元素的中值(或第 n 个最小整数)。例如,X = (4, 5, 7, 8, 9) 且 Y = (3, 5, 8, 9, 10),则 7 是组合列表 (3, 4, 5, 5, 7) 的中位数、8、8、9、9、10)。 [提示:使用二分搜索的概念]


我必须承认,当你第一次看到 O(log n) 算法时,这很奇怪……这个对数到底是从哪里来的?然而,事实证明,有几种不同的方法可以让对数项以大 O 表示法显示。以下是一些:

反复除以一个常数

取任意数n;比如说,16。在得到小于或等于 1 的数之前,你能将 n 除以 2 多少次?对于 16 岁,我们有

16 / 2 = 8
 8 / 2 = 4
 4 / 2 = 2
 2 / 2 = 1

Notice that this ends up taking four steps to complete. Interestingly, we also have that log2 16 = 4. Hmmm... what about 128?

128 / 2 = 64
 64 / 2 = 32
 32 / 2 = 16
 16 / 2 = 8
  8 / 2 = 4
  4 / 2 = 2
  2 / 2 = 1

This took seven steps, and log2 128 = 7. Is this a coincidence? Nope! There's a good reason for this. Suppose that we divide a number n by 2 i times. Then we get the number n / 2i. If we want to solve for the value of i where this value is at most 1, we get

n / 2i ≤ 1

n ≤ 2i

log2 n ≤ i

In other words, if we pick an integer i such that i ≥ log2 n, then after dividing n in half i times we'll have a value that is at most 1. The smallest i for which this is guaranteed is roughly log2 n, so if we have an algorithm that divides by 2 until the number gets sufficiently small, then we can say that it terminates in O(log n) steps.

An important detail is that it doesn't matter what constant you're dividing n by (as long as it's greater than one); if you divide by the constant k, it will take logk n steps to reach 1. Thus any algorithm that repeatedly divides the input size by some fraction will need O(log n) iterations to terminate. Those iterations might take a lot of time and so the net runtime needn't be O(log n), but the number of steps will be logarithmic.

那么这是从哪里出现的呢?一个经典的例子是二分查找,一种用于在排序数组中搜索值的快速​​算法。该算法的工作原理如下:

  • 如果数组为空,则返回该元素不存在于数组中。
  • Otherwise:
    • 查看数组的中间元素。
    • 如果它等于我们要查找的元素,则返回成功。
    • If it's greater than the element we're looking for:
      • 丢弃数组的后半部分。
      • Repeat
    • If it's less than the the element we're looking for:
      • 丢弃数组的前半部分。
      • Repeat

例如,要在数组中搜索 5

1   3   5   7   9   11   13

我们首先看中间的元素:

1   3   5   7   9   11   13
            ^

由于 7 > 5,并且由于数组已排序,因此我们知道数字 5 不可能位于数组的后半部分,因此我们可以将其丢弃。这留下

1   3   5

现在我们看看中间的元素:

1   3   5
    ^

由于3

        5

我们再次查看该数组的中间:

        5
        ^

由于这正是我们要查找的数字,因此我们可以报告 5 确实在数组中。

那么这有多有效呢?好吧,在每次迭代中,我们都会丢弃至少一半的剩余数组元素。一旦数组为空或者我们找到了我们想要的值,算法就会停止。在最坏的情况下,元素不存在,因此我们不断将数组的大小减半,直到用完元素。这需要多长时间?好吧,由于我们一遍又一遍地将数组切成两半,所以我们最多会在 O(log n) 次迭代中完成,因为在运行之前我们不能将数组切成两半超过 O(log n) 次超出数组元素。

遵循一般技术的算法分而治之(将问题切成碎片,解决这些碎片,然后将问题重新组合在一起)出于同样的原因往往会在其中使用对数项 - 你不能将某个对象切成两半超过 O(log n) 次。您可能想看看归并排序就是一个很好的例子。

一次处理一位数字的值

How many digits are in the base-10 number n? Well, if there are k digits in the number, then we'd have that the biggest digit is some multiple of 10k. The largest k-digit number is 999...9, k times, and this is equal to 10k + 1 - 1. Consequently, if we know that n has k digits in it, then we know that the value of n is at most 10k + 1 - 1. If we want to solve for k in terms of n, we get

n ≤ 10k+1 - 1

n + 1 ≤ 10k+1

log10 (n + 1) ≤ k + 1

(log10 (n + 1)) - 1 ≤ k

由此我们得知 k 大约是 n 的以 10 为底的对数。换句话说,n 中的位数是 O(log n)。

例如,让我们考虑一下将两个大数字相加的复杂性,这两个数字太大而无法放入机器字中。假设这些数字以 10 为基数表示,我们将这些数字称为 m 和 n。添加它们的一种方法是通过小学方法 - 一次写出一位数字,然后从右到左进行计算。例如,要将 1337 和 2065 相加,我们首先将数字写为

    1  3  3  7
+   2  0  6  5
==============

我们添加最后一位数字并进位 1:

          1
    1  3  3  7
+   2  0  6  5
==============
             2

然后我们添加倒数第二个(“倒数第二个”)数字并携带 1:

       1  1
    1  3  3  7
+   2  0  6  5
==============
          0  2

接下来,我们添加倒数第三个(“倒数第二个”)数字:

       1  1
    1  3  3  7
+   2  0  6  5
==============
       4  0  2

最后,我们添加倒数第四个(“preantepenultimate”......我喜欢英语)数字:

       1  1
    1  3  3  7
+   2  0  6  5
==============
    3  4  0  2

现在,我们做了多少工作?我们对每个数字总共执行 O(1) 次工作(即恒定量的工作),需要处理的数字总数为 O(max{log n, log m})。这总共给出了 O(max{log n, log m}) 复杂度,因为我们需要访问两个数字中的每个数字。

许多算法通过在某个基数中一次处理一位数字来获得 O(log n) 项。一个经典的例子是基数排序,一次对整数进行一位数排序。基数排序有多种形式,但它们通常运行时间为 O(n log U),其中 U 是要排序的最大可能整数。原因是每次排序都需要 O(n) 时间,并且总共需要 O(log U) 次迭代来处理正在排序的最大数字的每个 O(log U) 数字。许多先进的算法,例如Gabow 的最短路径算法或缩放版本Ford-Fulkerson 最大流量算法,其复杂性有一个对数项,因为它们一次只处理一位数字。


至于你如何解决这个问题的第二个问题,你可能想看看这个相关问题它探索了更高级的应用程序。鉴于此处描述的问题的一般结构,当您知道结果中存在对数项时,您现在可以更好地了解如何思考问题,因此我建议您在给出答案之前不要查看答案一些想法。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

什么会导致算法具有 O(log n) 复杂度? 的相关文章

  • 数组中的重复元素[重复]

    这个问题在这里已经有答案了 这有点与this https stackoverflow com questions 2605766 how to find a duplicate element in an array of shuffled
  • 为什么我的 Project Euler Problem 12 算法这么慢?

    我已经在 Scala 中为 PE P12 创建了解决方案 但速度非常非常慢 有人可以告诉我为什么吗 如何优化这个 calculateDevisors 简单的方法和calculateNumberOfDivisors 除数函数具有相同的速度 i
  • 将整数列表划分为总和相等的 K 个子列表

    类似的问题还有1 https stackoverflow com questions 27322804 partition of a set into k disjoint subsets with equal sum and 2 http
  • 用于基本要素匹配的最坏情况 NlogN 算法

    查找两个相同大小数组的元素之间的唯一映射 https stackoverflow com questions 4411940 find the unique mapping between elements of two same size
  • 关于大O和大Omega的问题

    我认为这可能是一个关于大 O 表示法的初学者问题 举例来说 我有一个算法 可以递归地分解整个列表 O n 然后将其重新组合在一起 O n 我假设这意味着效率为 O n O n 这是否可以简化为 2O n O 2n 或 O n 根据我对这种表
  • 对给定预定义顺序的字符串列表进行排序

    我有一系列颜色 我想按顺序排序 但是 我不想使用它们的 自然 顺序对它们进行排序 而是让它们保持以下顺序 var order white yellow violet blue orange red maroon brown black 例如
  • Python 中的空填字游戏求解器

    我得到了一个包含填字游戏蓝图的矩阵 当然 它是空的 我们的目标是填补整个难题 这是 Checkio 的一项任务 我已经为此奋斗了相当长一段时间 根据我对复杂性的理解 这个问题没有完美的算法 不过 必须有最好的方法来做到这一点 对吧 我尝试了
  • 图像算法上的物体计数

    我又接到学校任务了 这次 我的老师给我的任务是创建算法来计算图片上有多少只鸭子 该图与此类似 我想我应该使用模式识别来搜索上面有多少只鸭子 但我不知道每只鸭子适合哪种图案 我认为你可以通过分割鸭嘴并计算鸭嘴的数量来解决这个问题连接的组件 h
  • 如何设计一种算法来计算倒数式数学数字难题

    我一直想这样做 但每次我开始思考这个问题时 它的指数性质都会让我大吃一惊 我希望能够理解的问题解决器和代码是针对倒计时数学问题的 给定一组数字 X1 到 X5 计算如何使用数学运算将它们组合起来生成 Y 您可以应用乘法 除法 加法和减法 那
  • 处理流星中的长服务器端计算

    我正在使用 jimp https www npmjs com package jimp https www npmjs com package jimp 在meteor JS中生成图像服务器端 换句话说 我正在使用递归算法 计算 图像的像素
  • 查找文本中所有关键字的有效算法

    我有很多字符串 其中包含许多不同拼写的文本 我通过搜索关键字来标记这些字符串 如果找到关键字 我将使用该关键字的关联文本 假设搜索字符串可以包含文本 schw schwa 和 施瓦茨 我有三个关键字 全部解析为文本 schwarz 现在我正
  • 有效地合并两个数组 - 一个已排序,另一个未排序

    我正在解决一个问题 该问题有一个由 n 个元素组成的排序数组 后跟一个未排序的长度数组 O logn O 平方 n 如何最有效地对整个列表进行排序 在上述两种情况下我应该使用哪种排序 由于将单个元素插入数组并保持其排序是O n 你不可能变得
  • 在 3d 网格中转发(绘制)线

    我需要类似 Bresenham 算法的东西 但是 对于 3d 网格空间来说不完全是这样 我需要 3d 单元网格 边缘尺寸 1 0 从 S 点开始 前进到 K 点 接触 该线接触的所有单元格 即使只有边缘 点被触摸我需要触摸所有 8 个单元
  • 一种良好且简单的随机性测量方法

    获取一长整数序列 例如 100 000 个 并返回序列随机性的测量值的最佳算法是什么 该函数应返回单个结果 如果序列并非完全随机 则返回 0 如果完全随机 则返回 1 如果序列有点随机 它可以给出介于两者之间的东西 例如0 95 可能是一个
  • 素数生成器算法

    我一直在尝试解决素数生成算法的SPOJ问题 这是问题 彼得想为他的密码系统生成一些素数 帮助 他 你的任务是生成两个给定之间的所有素数 数字 Input 输入以单行中测试用例的数量 t 开始 t Output 对于每个测试用例 打印所有素数
  • 线段树java实现[关闭]

    Closed 这个问题正在寻求书籍 工具 软件库等的推荐 不满足堆栈溢出指南 help closed questions 目前不接受答案 你知道 二进制 的良好实现吗线段树 http en wikipedia org wiki Segmen
  • 定点数学比浮点运算快吗?

    多年前 即 20 世纪 90 年代初期 我构建了图形软件包 该软件包基于定点算术和预先计算的 cos sin 表格以及使用牛顿近似方法进行 sqrt 和对数近似的缩放方程来优化计算 这些先进技术似乎已经成为图形和内置数学处理器的一部分 大约
  • 什么是“朴素”算法,什么是“封闭式”解决方案?

    我有一些关于描述算法时使用的术语语义的问题 首先 朴素 算法是什么意思 这与给定问题的其他解决方案有何不同 解决方案还可以采取哪些其他形式 其次 我听到很多人提到 封闭式 解决方案 我也不知道这意味着什么 但在尝试解决递归关系时经常会出现
  • 如何求两个地点的经纬度距离?

    我有一组位置的纬度和经度 怎么找distance从集合中的一个位置到另一个位置 有公式吗 半正矢公式假定地球是球形的 然而 地球的形状更为复杂 扁球体模型会给出更好的结果 如果需要这样的精度 你应该更好地使用文森特逆公式 See http
  • LRU算法,实现这个算法需要多少位?

    我有一个关于 LRU 算法的小问题 如果您有一个包含四个块的高速缓存 那么需要多少位来实现该算法 假设您指的是 4 路组关联缓存 完美 LRU 本质上是按照使用顺序为每一行分配一个精确的索引 您也可以将其视为 年龄 因此 4 个元素中的每一

随机推荐

  • WPF TextFormatter 中第二行的缩进

    我正在使用 TextFormatter 制作 WPF 文本编辑器 我需要缩进每个段落中的第二行 第二行的缩进宽度应该与第一行第一个单词的宽度相同 包括第一个单词后面的空白 像这样的东西 Indent of second line in In
  • 从 Flutter 打开 Android Activity 和 iOS ViewController

    我有一个 Flutter 项目 需要一些需要在本机 Android Activity 或 iOS ViewController 中实现的某些功能 有没有办法导航到 android Activity 并向其传递数据 并在 Flutter 中从
  • 带有 MediaCodec Surface 的 AVC 硬件编码器可靠性如何?

    我正在开发一个 Android 应用程序 该应用程序使用 MediaCodec 使用 Surface 方法对 H 264 视频进行编码 我的目标是 Android 5 0 并且遵循了 bigflake com 中的所有示例和样本 我两年前开
  • MATLAB 中的矩阵乘法时间复杂度

    有谁知道MATLAB使用哪种算法进行矩阵乘法以及它的时间复杂度是多少 为了完整起见 如中所述这个线程 Matlab 使用DGEMM 双通用矩阵乘法 例程来自BLAS 基本线性代数子程序 请注意 BLAS 不存在单一的实现 它针对特定的处理器
  • newtonsoft json序列化时间跨度格式

    是否可以指定自定义格式TimeSpan序列化 使用Newtonsoft Json 我想要格式为 HH mm 的序列化字符串 例如 TimeSpan FromHours 5 gt 05 00 TimeSpan FromHours 5 gt 0
  • 更好的 git add -p 吗?

    有时我在没有安装 X Window 的系统上工作 并且无法使用 Git GUI 现有的控制台替代品是什么git add p 我几乎喜欢它所做的一切 实际上比 Git GUI 更喜欢 但我讨厌它不允许我查看整个图片并选择我想要查看块的顺序 这
  • .forEach 中 thisArg 的用途是什么?

    JavaScript 的对于每个文档指出 forEach语法是 arr forEach callback thisArg 有什么用thisArg The thisArg可以提供改变inner this的回调函数 未指定thisArg结果是t
  • 导入 theano 时出错“无法导入名称 gof”

    我目前收到错误 导入错误 无法导入名称 gof 导入 theano 时 gt gt gt import theano Traceback most recent call last File
  • 延迟生成 powerset

    我想计算一个集合的幂集 因为我不需要一次需要整个 powerset 所以最好延迟生成它 例如 powerset set a b c seq set set a set b set c set a b set a c set b c set
  • 组合 R + awk + ​​bash 命令

    我想结合awk和R语言 问题是我在指定目录中有一组 txt 文件 并且我不知道文件头的长度 在某些情况下 我必须跳过 25 行 而在其他情况下 我必须跳过 27 行等 所以我想输入一些 awk 命令来获取要跳过的行数 一旦获得该值 我就可以
  • 当初始化固定大小的 char 数组时没有足够的空间容纳 null 终止符时,不会出现编译器错误

    假设我有以下 c char 数组 char okaysize4 5 four line 5 char toosmall4 4 four line 6 char toosmall3 3 four line 7 当我使用 gcc 4 4 7 编
  • ES6 模板文字 - 从字符串中删除 \n

    我正在将多行变量更改为Template Literals太神奇了 但后来我注意到我所做的缩进被转换 缩小 为 n与我在原始代码上所做的缩进 我怎样才能避免这种情况 Ex var div div class proj div class bo
  • 如何在 Windows 窗体中模仿 JavaScript 的 onBlur 事件?

    我在 Windows 窗体上有电话和电子邮件文本框 我想在用户离开字段时对其进行验证 当我双击 Visual Studio 表单设计器中的文本框时 它会创建一个textchanged事件 这不太合适 因为仅当用户输入完整条目时才调用验证方法
  • 如何检查 perl 中是否声明了变量?

    我在用use strict 在 perl 中 我使用以下语句 unless defined x print Not defined 其中 x 没有在任何地方声明 所以我希望它打印 Not defined 但它返回一个错误 Global sy
  • 创建 JSONObject 时 org.json 未报告异常

    谁能帮助我理解出了什么问题 unreported exception org json JSONException must be caught or declared to be thrown jsonObj new JSONObject
  • 将浮点数组转换为字符串的最快方法是什么? [复制]

    这个问题在这里已经有答案了 在 C 中将浮点数组转换为字符串的最快方法是什么 如果我的数组包含这个 0 1 1 1 1 0 0 2 然后我希望每个条目转换为一个字符串 其值由空格分隔 即 0 1 1 1 1 0 0 2 我会选择最具可读性的
  • 在数据框上使用 If/Else

    我有一个数据集 看起来像 data lt c 0 1 2 3 4 2 3 1 4 3 2 4 0 1 2 0 2 1 2 0 4 frame lt as data frame data 我现在想在此数据框中创建一个新变量 如果 数据 列报告
  • Laravel 5 - 查找模型的分页页面

    我正在努力建立一个基本论坛 灵感来自laracasts com 讨论 当用户发布对主题的回复时 我想引导他们到列表的末尾分页回复及其回复的锚点 与 Laracasts 的行为相同 我还想在用户编辑回复之一时将其返回到正确的页面 我怎样才能知
  • LinkedList 上的 LINQ - 迭代 LinkedListNode,而不是 T

    我在理解如何在 LINQ 中执行某些操作时遇到问题 我有一个链表 对象的类型并不重要 重要的是我想做一些事情Where 基于当前对象之间的关系以及列表中的下一个 为什么我不能做类似的事情 linkedlist Where n gt a fu
  • 什么会导致算法具有 O(log n) 复杂度?

    我对大 O 的了解是有限的 当对数项出现在方程中时 它让我更加困惑 有人可以用简单的语言向我解释一下什么是O log n 算法是 对数从何而来 当我试图解决这个期中练习题时 特别出现了这个问题 令 X 1 n 和 Y 1 n 包含两个整数列