【发布时间】:2020-03-04 16:58:06
【问题描述】:
我正在寻找以下问题的内存和省时解决方案。很容易想到一个使用 O(n2) 内存和 O(n2 log n) 时间(?)的基本算法,我想知道如果有一种算法显着提高内存和时间效率(对于某些输入结构)。
输入:长度为 n 的数组 a 填充有非负整数。数组中的每个整数的大小都小于或等于 b。我对 n 较大(数千万)且 b 与 n(数百)相比相对较小的设置感兴趣。我们可以假设 a 中任何特定整数的出现次数都以 m 为界,其中 m 的数量级为 n/b。
考虑数组 a 的所有旋转的集合,即如果 a = (a1, a2, ..., an), 那么它的旋转是 (a1, a2, ..., an), (a 2, a3, ..., an, a1), (a3, a4, ..., an, a1, a2), ... , (an, a1, a2, ..., an-1)。令 r1, r2, ..., rn 表示数组 a 的旋转按字典顺序(递增)排序(使用0
输出:两个数组first和last,分别存储r1、r的第一个和最后一个元素2, ..., rn 按排序顺序。 基本算法(不是内存或时间效率):构造 a 的所有旋转并将它们存储在矩阵 A 中(使用 O(n2) 内存) .定义一个排序例程(使用标准排序技术)对 A 进行排序。提取排序矩阵的第一列和最后一列。推测排序步骤的最佳时间复杂度为 O(n2 log n),即排序算法的 O(n log n) 乘以每个成对比较的 O(n)。 第二种算法:我们可以遍历数组并在其中存储以小于或等于 b 的任何整数 i 开头的位置(这是 O(n) 时间和 O(nm ) 记忆操作)。然后,我们可以从一个特定的整数 i 开始生成所有旋转,并按照基本算法对这个旋转矩阵进行排序(存储这个矩阵使用 O(nm) 内存,排序大概需要 O(mn log m) 时间)。通过对从 0 到 b 的每个整数 i 重复该过程,很容易构造输出。 是否有一种使用定制排序策略的内存效率更高的方法?我很有希望,因为存储输出只需要 O(n) 内存。
【问题讨论】:
-
我认为你的第一个算法很好,但你不必创建整个矩阵。通过偏移量来识别每个旋转并调整排序中使用的比较应该就足够了。或者,将数组加倍 (1, 2, 3, ..., n, 1, 2, 3, ...) 并使用标准排序算法将切片/视图排序到该数组中。
-
@MOehm 感谢您的建议。那么 O(n^2 log n) 在时间复杂度上我能做到的最好吗?
-
为什么是 O(n² log n)?排序应该是 O(n log n)。创建要排序和输出的向量是 O(n)。额外的内存是 O(n)。
-
@MOehm 排序步骤的数量可以是 O(n log n) 并且每个成对比较是 O(n),不是吗?也许成对比较实际上更快
-
啊,我明白了。但 O(n) 是比较的上限。
标签: arrays algorithm sorting rotation memory-efficient