使用quickselect

给定一个既包含负值又包含正值的数组,我如何找到最接近中位数的第k个元素?我有一个快速选择方法,可以找到数组的中位数。然后,我遍历原始数组并创建另一个数组diff,在其中我将数组中每个元素的绝对值减去中值(abs(a[i]-median))。但是,我不知道如何修改我的quickselect和分区来实现此目的。这就是我目前所拥有的。

在数组a的中间找到值:

midpoint=int(len(a)/2)
median=quickSelect(a,len(a)-1,midpoint)

quickSelect如下所示:

def quickSelect(array,start,end,k):

    if start>=end:
        return array[k]

    value=partition(array,end)

    if value>k:
        return quickSelect(array,value-1,k)
    else:
       return quickSelect(array,value+1,k)

partition方法如下:

def partition(array,end):
    x=start-1
    #pivot is the last element at each iteration
    pivot=array[end]

    for i in range(start,end):
        if array[i]<=pivot:
            x+=1
            array[x],array[i]=array[i],array[x]        
    array[x+1],array[end]=array[end],array[x+1]
    return x+1

然后我存储差异的绝对值:

diff=[None]*len(a)     
for x in range(len(a)):
    diff[x]=abs(a[x]-median)

在这一点上,我不知道要对用来查找数组中位数的新的快速选择和分区函数进行哪些修改。

具有数组[10,4,2,15,18]k=2的示例输出为4,15

编辑: 我认为我已经接近解决方案,但是当数组大小较大时,我的新代码将失败。我创建了没有绝对值(diff)的数组diff[x]=a[x]-median

然后我将值在中间的位置切换为0(diff[midpoint],diff[0]=diff[0],diff[midpoint]),因为没有什么比中间值的绝对值减去值本身小。

然后,我创建了一个quickSelectKClosest函数,该函数调用考虑绝对值的partitionAbsoluteValue方法。

quickSelectKClosest

    def quickSelectKClosest(array,k):

        if start>=end:
            return array[k]

        value=partitionAbsoluteValue(array,end)

        if value>k:
            return quickSelectKClosest(array,k)
        else:
            return quickSelectKClosest(array,k)

partitionAbsoluteValue

def partitionAbsoluteValue(array,end):
    x=start-1
    pivot=array[end]

    for i in range(start,end):
        if abs(array[i])<=abs(pivot):
            x+=1
            array[x],array[x+1]

    return x+1

然后回到main,我这样叫quickSelectKClosest

val=quickSelectKClosest(diff,1,len(diff)-1,1+k)

以1作为开始,1+k作为第k个值(因为0在diff[0]处)

然后我发现quickSelectKClosest返回的值的位置:

indexOfKthLargest=diff.index(val)

最后遍历diff数组,然后将值添加到中间后面:

for x in range(1,indexOfKthLargest+1):
    print(diff[x]+median)

但是如果我有一个数组:[16,-23,53,19,-39,99,84,95,7,6,64,-79,89,43,41]

k=3

输出不完全正确:

The median was:  41 
The kth closest to the median are
43
53
19

我忘了提及这一点,但是数组中的值是唯一的,因此不会重复。

a932182372 回答:使用quickselect

由于使用的是quickselect,请选择2k个元素(如果n为偶数)或2k + 1个元素(如果n为奇数),以中位数为中心,然后使用双索引技术选择一个长度为k的子列表。初始化两个索引ij到中位数的左右,然后将i向下或j向上计数,直到从i到{{ 1}}包括中位数和另外j个元素。

在此示例中,使用k

k = 2

以中位数为中心的2k + 1个元素是[16,-23,53,19,-39,99,84,95,7,6,64,-79,89,43,41] ,按排序顺序。中位数本身是mids = [16,41,53]

  • 初始化双索引技术的mids[2]i = 1
  • j = 3mids[j]更接近中位数,因此将mids[i]增至4。
  • j仍然比mids[j]更接近中位数,因此将mids[i]增至5。
  • 现在停止j。最接近中位数的j - i - 2 >= k数字在以下范围内:
    • 排除左边界k
    • 排除索引2的中位数本身。
    • 在索引3处包含值为43。
    • 在索引4处包含值为53。

结果是i = 1

本文链接:https://www.f2er.com/3112240.html

大家都在问