我可以使用中位数选择算法的中位数来找出O(n)中的中位数。此外,我知道在算法完成后,中位数左边的所有元素都小于中位数,右边的所有元素都大于中位数。但是如何在O(n)时间内找到k个最近邻居的中位数?
如果中位数为n,则左侧的数字小于n,右侧的数字大于n。 但是,数组未在左侧或右侧排序。数字是用户给出的任何一组不同的数字。
问题来自Cormen的算法导论,问题9.3-7
答案 0 :(得分:17)
似乎没有人有这个。这是怎么做的。首先,如上所述找到中值。这是O(n)。现在将中位数停在数组的末尾,并从每个其他元素中减去中位数。现在再次使用快速选择算法找到数组的元素k(不包括最后一个元素)。这不仅找到元素k(按顺序),它还离开数组,使得最低的k数位于数组的开头。一旦你将中位数加回来,这些是最接近中位数的k。
答案 1 :(得分:8)
中位数的中位数可能对找到最近的邻居没有太大帮助,至少对于大n来说。是的,你的每列都有5个分区的中位数,但这还不足以解决问题。
我只是将中位数视为中间结果,并将最近邻居视为优先队列问题......
一旦你得到中位数中位数的中位数,记下它的值。
对所有数据运行heapify算法 - 请参阅Wikipedia - Binary Heap。在比较中,将结果基于相对于保存的中值的差异。优先级最高的项目是ABS(值 - 中位数)最低的项目。这需要O(n)。
数组中的第一项现在是中位数(或它的副本),并且数组具有堆结构。使用堆提取算法根据需要提取尽可能多的最近邻居。对于k个最近邻居,这是O(k log n)。
只要k是一个常数,你得到中位数的O(n)中位数,O(n)堆积和O(log n)提取,总得O(n)。
答案 2 :(得分:4)
med=Select(A,1,n,n/2) //finds the median
for i=1 to n
B[i]=mod(A[i]-med)
q=Select(B,1,n,k) //get the kth smallest difference
j=0
for i=1 to n
if B[i]<=q
C[j]=A[i] //A[i], the real value should be assigned instead of B[i] which is only the difference between A[i] and median.
j++
return C
答案 3 :(得分:2)
您可以像这样解决问题:
你可以在O(n)中找到中位数,w.g。使用O(n)nth_element算法。
循环遍历所有使用一对替换的元素:
the absolute difference to the median, element's value.
再次使用n = k进行nth_element。应用此算法后,您可以保证在新数组中首先具有绝对差异中的k个最小元素。你拿他们的指数并完成!
答案 4 :(得分:0)
您已经知道如何在O(n)中找到中位数
如果顺序无关紧要,可以在O(n)中选择k最小 将k最小值应用于中位数的rhs,将k最大值应用于中位数的lhs
function findFirstK(list, left, right, k)
if right > left
select pivotIndex between left and right
pivotNewIndex := partition(list, left, right, pivotIndex)
if pivotNewIndex > k // new condition
findFirstK(list, left, pivotNewIndex-1, k)
if pivotNewIndex < k
findFirstK(list, pivotNewIndex+1, right, k)
不要忘记k == n返回原始列表的特殊情况
答案 5 :(得分:0)
您可以在数字列表L
上使用非比较排序(例如基数排序),然后通过考虑k个元素的窗口并检查窗口端点来找到k个最近邻居。另一种说明“找到窗口”的方法是找到最小化abs(L[(n-k)/2+i] - L[n/2]) + abs(L[(n+k)/2+i] - L[n/2])
(如果k为奇数)或abs(L[(n-k)/2+i] - L[n/2]) + abs(L[(n+k)/2+i+1] - L[n/2])
(如果k为偶数)的最小化。结合案例abs(L[(n-k)/2+i] - L[n/2]) + abs(L[(n+k)/2+i+!(k&1)] - L[n/2])
。找到最小值的简单O(k)方法是从i = 0开始,然后向左或向右滑动,但是你应该能够在O(log(k))中找到最小值。
您最小化的表达式来自将L
转换为另一个列表M
,方法是从中位数中取出每个元素的差异。
m=L[n/2]
M=abs(L-m)
i
最小化M[n/2-k/2+i] + M[n/2+k/2+i]
。
答案 6 :(得分:0)
实际上,答案很简单。我们需要做的就是选择k个元素,当中位数为m时,中值从m-1移动到0,m + 1到n-1的绝对差值最小。我们使用我们在合并2个排序数组时使用的相同想法来选择元素。
答案 7 :(得分:0)
四个步骤:
答案 8 :(得分:0)
答案 9 :(得分:0)
所有建议从数组中减去中位数的答案都会产生错误的结果。此方法将查找值最接近而不是位置最接近的元素。
例如,如果数组为1,2,3,4,5,10,20,30,40
。对于k = 2,返回的值为(3,4);这是不正确的。正确的输出应该是(4,10),因为它们是最近的邻居。
查找结果的正确方法是使用选择算法查找上下限元素。然后通过直接比较从列表中找到剩余的元素。
答案 10 :(得分:-1)
如果你知道中位数的索引,它应该只是ceil(array.length / 2),那么它应该是列出n(xk),n(x-k + 1)的过程, ...,n(x),n(x + 1),n(x + 2),... n(x + k) 其中n是数组,x是中位数的索引,k是你需要的邻居数。(如果你想要总k,可能是k / 2,而不是每边k)
答案 11 :(得分:-1)
首先使用该复杂度的standard algorithm在O(n)
时间内选择中位数。
然后再次浏览列表,选择最接近中位数的元素(通过存储最知名的候选者并将新值与这些候选者进行比较,就像搜索最大元素一样)。
在通过列表的额外运行的每个步骤中,需要O(k)步骤,并且因为k是常数,所以这是O(1)。因此,额外运行所需的总时间为O(n),完整算法的总运行时间也是如此。
答案 12 :(得分:-1)
由于所有元素都是不同的,因此最多可以有2个元素与平均值具有相同的差异。我认为让2个数组A [k]和B [k]更容易表示与均值的差值的绝对值。现在的任务是填充数组并通过读取A [i + 1]和B [i + 1]之前读取A [i]和B [i]的数组的前k个非空值来选择k个元素。这可以在O(n)时间内完成。