【问题标题】:Finding the Kth Closest Elements to the median using quickselect使用快速选择查找离中位数最近的第 K 个元素
【发布时间】:2019-11-17 08:35:47
【问题描述】:

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

在数组a的中间找到值:

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

quickSelect 看起来像这样:

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

    if start>=end:
        return array[k]

    value=partition(array,start,end)

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

partition 方法如下所示:

def partition(array,start,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,start,end,k):

        if start>=end:
            return array[k]

        value=partitionAbsoluteValue(array,start,end)

        if value>k:
            return quickSelectKClosest(array,start,value-1,k)
        else:
            return quickSelectKClosest(array,value+1,end,k)

partitionAbsoluteValue:

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

    for i in range(start,end):
        if abs(array[i])<=abs(pivot):
            x+=1
            array[x],array[i]=array[i],array[x]        
    array[x+1],array[end]=array[end],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

我忘了提这个,但是数组中的值是唯一的,所以它们不会重复。

【问题讨论】:

  • quickSelect(a,0,len(a)-1,midpoint-k)quickSelect(a,0,len(a)-1,midpoint+k) 怎么样?
  • 你是否受限于 python 2 ?
  • @WalterTross 我不限于 python 2。

标签: python algorithm


【解决方案1】:

由于您使用的是快速选择,因此选择以中位数为中心的 2k 个元素(如果 n 为偶数)或 2k + 1 个元素(如果 n 为奇数),然后使用双索引技术选择长度为 k 的子列表。初始化两个索引ij到中间值的左右,向下计数i或者j直到ij的范围包括中间值和k其他元素.

对于这个例子,k = 2:

[16, -23, 53, 19, -39, 99, 84, 95, 7, 6, 64, -79, 89, 43, 41]

以中位数为中心的 2k + 1 个元素按排序顺序排列为 mids = [16, 19, 41, 43, 53]。中位数本身是mids[2]

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

所以结果是[43, 53]

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-06-23
    • 2021-06-07
    • 1970-01-01
    • 1970-01-01
    • 2021-03-03
    • 2018-03-16
    • 2021-09-05
    相关资源
    最近更新 更多