给定一个包含 N 个整数的数组,将该数组排序,并找到排序后相邻两个数之间差值最大的一对。
例如:对于输入的数组[1,7,3,2]
,输出4
(排序后的数组为[1,2,3,7]
,最大差值为 7-3=4)。
算法A的时间复杂度为O(NlogN)
。
我需要寻找一种与算法A功能相同的算法,但时间复杂度为O(N)
。
将数组X命名为X,令n = length(X)。将每个元素x放入桶号floor((x-min(X))*(n-1)/(max(X)-min(X)))中。每个桶的宽度为(max(X)-min(X))/(n-1),相邻的最大差距至少是这么多,因此相关数字最终被放在不同的桶中。现在我们只需要考虑一些特定的数对,其中一个是桶i中的最大值,另一个是桶j中的最小值,其中i < j并且(i, j)之间的所有桶都为空。这是线性时间。
证明我们确实需要floor:令函数为f(X)。如果我们可以在线性时间内计算f(X),那么我们肯定可以在线性时间内决定
0 < f(X) ≤ (max(X) - min(X))/(length(X) - 1),
即X的元素是否均匀分布并且不完全相同。让这个谓词为P(X)。P的支持有阶乘(length(X))个连通组件,因此对于计算模型的代数模型,通常的Ω(n log n)下限适用。
B[0...n-2]
是n-1
个桶,那么您还需要考虑对(min(X), min(B[0]))
和(max(X), max(B[n-2]))
这两对的处理。 - Raghubansh Mani执行计数排序,然后扫描结果以找到最大差异。
由于连续数字的要求,乍一看似乎任何解决方案都需要排序,这意味着最好情况下是O(n log n),除非您的数字范围足够受限以进行计数排序。但如果是这样,您将获得O(n)的胜利。
现在,首先尝试想一想,如果您已经在大小为N的数组中给出了最小值MIN和最大值MAX,在什么情况下最大间隙会最小或最大?
显然,当所有元素都是MIN或MAX时,最大间隙将达到最大值,使得maxgap = MAX - MIN。
当所有元素在MIN和MAX之间等间隔排列时,最大间隙将达到最小值。假设它们之间的间隔是gap。
因此,它们被排列为
MIN, MIN + gap, MIN + 2*gap, MIN + 3*gap, ... MIN + (N-1)*gap
where
MIN + (N-1)*gap = MAX .
gap = (MAX - MIN) / (N - 1).
所以,我们现在知道答案将在范围 [间隙,MAX - MIN]
内。现在,如果我们知道答案大于间隙,我们要做的是为范围创建大小为间隙的桶。
[MIN, MIN + gap), [Min + gap, `MIN` + 2* gap) ... and so on
只会有(N-1)
个这样的桶。我们根据它们的值将数字放入这些桶中。
如果您从单个桶中选择任意2个数字,则它们的差将小于间隙,因此它们永远不会对maxgap
产生贡献(请记住maxgap >= gap
)。我们只需要存储每个桶中最大和最小的数字,并且我们只查看跨桶的数字。
现在,我们只需要按顺序遍历桶(它们已经按值排序),并获取具有至少一个值的前一个桶的min_value与max_value之间的差异。我们取所有这些值的最大值。
int maximumGap(const vector<int> &num) {
if (num.empty() || num.size() < 2) return 0;
int maxNum = *max_element(num.begin(), num.end());
int minNum = *min_element(num.begin(), num.end());
//average gap from minNum to maxNum.
int gap = (maxNum - minNum - 1) / (num.size() - 1) + 1;
//number of buckets = num.size() - 1
vector<int> bucketsMin(num.size() - 1, INT_MAX);
vector<int> bucketsMax(num.size() - 1, INT_MIN);
//put into buckets
for (int i = 0; i < num.size(); i++)
{
if (num[i] != maxNum && num[i] != minNum)
{
int buckInd = (num[i] - minNum) / gap;
bucketsMin[buckInd] = min(bucketsMin[buckInd], num[i]);
bucketsMax[buckInd] = max(bucketsMax[buckInd], num[i]);
}
}
int maxGap = INT_MIN;
int previous = minNum;
for (int i = 0; i < num.size() - 1; i++)
{
if (bucketsMin[i] == INT_MAX && bucketsMax[i] == INT_MIN) continue; //empty
//i_th gap is minvalue in i+1_th bucket minus maxvalue in i_th bucket
maxGap = max(maxGap, bucketsMin[i] - previous);
previous = bucketsMax[i];
}
maxGap = max(maxGap, maxNum - previous);
return maxGap;
}
k
k
的值放在左边,大于 k
的值放在右边来排序算法。以下是此算法的示例:
我的算法与选择算法非常相似,可以在线性时间内找到排序算法的k索引值。
[1,9,2]
。在这种情况下,基数排序或计数排序不是正确的方法。 - user248884