在sum数组中找到第k个数字

时间:2015-02-28 16:22:38

标签: algorithm

给定具有N个元素的数组A,我需要找到对(i,j),使得i不等于j并且如果我们为所有对(i,i)写出和A [i] + A [j] j)然后它出现在第k位。

示例:设N = 4,数组A = [1 2 3 4],如果K = 3,则答案为5,因为我们可以清楚地看到sum数组变为这样:[3 ,4,5,5,6,7]

我不能去所有的i和j,因为N可以达到100000.请帮助解决这个问题

我的意思是这样的:

int len=N*(N+1)/2;
int sum[len];
int count=0;
for(int i=0;i<N;i++){
   for(int j=i+1;j<N;j++){
        sum[count]=A[i]+A[j]; 
        count++;
   }
}
//Then just find kth element.

我们不能采用这种方法

3 个答案:

答案 0 :(得分:0)

我假设你从http://www.careercup.com/question?id=7457663得到了这个问题。

如果k接近0,则How to find kth largest number in pairwise sums like setA + setB?的已接受答案可以很容易地适应此问题并且非常有效。您需要O(n log(n))对数组进行排序,O(n)以设置优先级队列,然后O(k log(k))来迭代元素。如果k接近n*n - n,反向解决方案也会有效。

如果k接近n*n/2那么那就不会很好。但是你可以调整http://en.wikipedia.org/wiki/Quickselect的支点方法来解决这个问题。首先是O(n log(n)),您可以对数组进行排序。在时间O(n)中,您可以设置表示各个连续列范围的数据结构。然后,您需要选择O(log(n))次枢轴。 (请记住,log(n*n) = O(log(n))。)对于每个数据透视表,您可以对每列进行二进制搜索,以确定每列的分割位置O(log(n)),以及O(n log(n))的总成本所有专栏。

生成的算法为O(n log(n) log(n))

更新:我没时间做手指提供代码。但我可以概述一些实现中可能具有的类。

实现有点冗长,但有时这是一个很好的通用算法的成本。

ArrayRangeWithAddend。这表示一个数组的范围,总和为一个值。具有array(引用或指针,因此基础数据可以在对象之间共享),startend到范围,以及要添加到范围中每个元素的值的shiftValue

它应该有一个构造函数。给出size的方法。一种方法partition(n)将其调整到小于n的范围,计数等于n,范围大于n。并value(i)提供i&#39;值。

ArrayRangeCollection。这是ArrayRangeWithAddend个对象的集合。它应该有方法来给出它的大小,选择一个random元素,并将partition(n)方法添加到ArrayRangeCollection n以下n,等于{ {1}}以及大于ArrayRangeCollection的{​​{1}}。在n方法中,最好不要包含大小为partition的{​​{1}}个对象。

现在您的主程序可以对数组进行排序,并创建一个涵盖您感兴趣的所有总和的ArrayRangeWithAddend。然后可以使用0ArrayRangeCollection方法来实现标准的quickselect算法,你可以在我提供的链接中找到。

答案 1 :(得分:0)

基于K <= 50的事实的解决方案:让我们按排序顺序获取数组的第一个K + 1元素。现在我们可以尝试他们所有的组合。正确性证明:我们假设一对(i, j)是答案,j > K + 1。但是K对具有相同或更小的总和:(1, 2), (1, 3), ..., (1, K + 1)。因此,它不能是K对。

通过使用quickselect算法选择O(N + K ^ 2)最小数字,可以实现K + 1时间复杂度(可能做得更好,但不是必需的)。您也可以只使用数组并获得O(N * log N + K ^ 2 * log K)复杂度。

答案 2 :(得分:0)

以下是如何做到这一点(伪代码)。我现在已经确认它可以正常工作。

//A is the original array, such as A=[1,2,3,4]
//k (an integer) is the element in the 'sum' array to find

N = A.length

//first we find i
i = -1
nl = N
k2 = k
while (k2 >= 0) {
    i++
    nl--
    k2 -= nl
}

//then we find j
j = k2 + nl + i + 1

//now compute the sum at index position k
kSum = A[i] + A[j]

编辑: 我现在测试了这个作品。我必须修复一些部分......基本上k输入参数应该使用基于0的索引。 (OP似乎使用基于1的索引。)

编辑2: 我会试着解释一下我的理论。我开始的概念是sum数组应该可视化为2D锯齿状数组(宽度随着高度的增加而减小),坐标(如OP中所述)为i和{{ 1}}。因此,对于像[1,2,3,4,5]这样的数组,j数组将被设想为:

sum

顶行是3,4,5,6, 5,6,7, 7,8, 9. 等于0的所有值。第二行是i等于1的位置。要找到'j'的值,我们会在列方向上执行相同的操作。

...对不起我无法解释这个更好!