在 nlog(n) 时间内对整数数组进行排序而不使用比较运算符

Posted

技术标签:

【中文标题】在 nlog(n) 时间内对整数数组进行排序而不使用比较运算符【英文标题】:Sorting an array of integers in nlog(n) time without using comparison operators 【发布时间】:2021-12-18 15:48:22 【问题描述】:

想象一下有一个整数数组,但不允许您访问任何值(所以没有Arr[i] > Arr[i+1] 或其他)。区分整数的唯一方法是使用 query() 函数:该函数将元素的子集作为输入,并返回该子集中唯一整数的数量。目标是根据整数的值将整数分组——同一组中的整数应该具有相同的值,而不同组中的整数具有不同的值。 问题 - 代码必须是 O(nlog(n)),或者换句话说 query() 函数只能被调用 O(nlog(n)) 次。

我花了好几个小时在 Python 中优化不同的算法,但所有的算法都是 O(n^2)。作为参考,这是我开始使用的代码:

n = 100
querycalls = 0
secretarray = [random.randint(0, n-1) for i in range(n)]
def query(items):
    global querycalls
    querycalls += 1
    return len(set(items))
groups = []

secretarray 生成一个长度为n 的巨大随机数字列表。 querycalls 跟踪函数被调用的次数。 groups 是结果所在。

我做的第一件事是尝试创建一个基于合并排序的算法(拆分数组,然后根据 query() 值合并),但我永远无法将它低于 O(n^2)。

【问题讨论】:

这是一个有趣的问题,但我认为标题具有误导性——“排序”意味着结果是有序的。我建议将其更改为“分区”。 【参考方案1】:

假设您有一个元素 x 和一个不同元素的数组 A = [x0, x1, ..., x_k-1] 并想知道 x 是否等同于数组中的某个元素,如果是,则等同于哪个元素。

你可以做的是一个简单的递归(我们称之为check-eq):

检查是否query([x, A]) == k + 1。如果是,那么您知道xA 中的每个元素都不同。 否则,您知道x 等价于A 的某个元素。让A1 = A[:k/2], A2 = A[k/2+1:]。如果query([x, A1]) == len(A1),那么你知道x等价于A1中的某个元素,所以在A1中递归。否则在A2中递归。

此递归最多需要O(logk) 个步骤。现在,让我们的初始数组为T = [x0, x1, ..., x_n-1]A 将是元素组的“代表”数组。您要做的是首先获取A = [x0]x = x1。现在使用check-eq 查看x1 是否与x0 在同一组中。如果没有,那么让A = [x0, x1]。否则什么都不做。继续x = x2。你可以看看它是怎么回事。

复杂性当然是O(nlogn),因为check-eq 被准确地调用了n-1 次并且每次调用都需要O(logn) 时间。

【讨论】:

以上是关于在 nlog(n) 时间内对整数数组进行排序而不使用比较运算符的主要内容,如果未能解决你的问题,请参考以下文章

leetcode:First Missing Positive分析和实现

使用 O(m) 空间在 O(n) 时间内对向量<int>(n) 进行排序?

java-数组排序--计数排序桶排序基数排序

c_cpp 使用常量空间复杂度在O(n log n)时间内对链表进行排序。

在数组的线性时间内排序,每个元素至少出现n / 1000次

对 32 位数字使用基数排序