从每对总和中找到第k个总和

时间:2018-06-22 14:07:46

标签: algorithm sequences

我给了具有n个元素的数组,我需要从时间对复杂度O(n * logn)的每对n ^ 2的总和中找到第k个总和,并且总和以升序排列。


示例输入

在第一行中给出了元素数量和要求和的数量。在第二行数字中,我们需要生成一对数字对。

 3 6
 1 4 6

给定列表的答案是8,下面是每对和的数组,其中8,4 + 4的和在第6位。

2 5 5 7 7 8 10 10 12

其中前三个元素如下所示

  • 1 + 1 = 2
  • 1 + 4 = 5
  • 4 + 1 = 5

编辑: 我想到了这一点,主要的问题是找到与元素本身相加的地方。我将举个例子使之更清楚。

对于序列[1、4、10],我们有

2 5 5 8 11 11 14 14 20

问题在于将4 + 4的和放置在哪里,这取决于1 + 10> 4 + 4,其他和具有固定的位置,因为第二个元素+ last将始终大于last + first(如果我们在升序)。

3 个答案:

答案 0 :(得分:1)

这可以在O(n log maxSum)中解决。

伪代码:

sort(array)
low = array[1] * 2
high = array[n] * 2
while (low <= high): (binarySearch between low and high)
    mid = floor((high + low) / 2)
    qty = checkHowManySumsAreEqualOrLessThan(mid)
    if qty >= k:
        high = mid - 1
    else:
        low = mid + 1
answer = low // low will be the first value of mid where qty was >= k. This means that on low - 1, qty was < k. This means the solution must be low

排序为O(n log n)。二进制搜索成本log(array [n] * 2-array [0] * 2)。

checkHowManySumsAreEqualOrLessThan(mid)可以使用2个指针在O(n)中完成,请让我知道您是否知道该怎么做。

之所以起作用,是因为即使我们不对k进行二进制搜索,也确实存在以下事实:如果有x个和<= mid,如果k x时相同。

答案 1 :(得分:0)

编辑:这是O(n ^ 2)

我理解问题的方式,第一行的第一个数字是数字,第二个数字是k。

您可以通过使用PriorityQueue来解决此问题,该队列在您输入数字时会为您排序所有内容。使用2个嵌套的for循环,以便它们访问每对一次。

    for(int k = 0; k < n; k++){
        for(int j = 0; j <= k; j++){

如果j == k,则将k + j输入到PriorityQueue中一次,否则输入两次总和。然后,遍历PriorityQueue以获得第6个值。

如果愿意,将使用完整的代码进行编辑。

答案 2 :(得分:0)

由于juvian解决了困难的部分,所以我能够编写此解决方案,评论应对此进行解释:

def count_sums_of_at_most(amount, nums1, nums2):

    p1 = 0  # Pointer into the first array, start at the beginning
    p2 = len(nums2) - 1  # Pointer into the second array, start at the end

    # Move p1 up and p2 down, walking through the "diagonal" in O(n)
    sum_count = 0
    while p1 < len(nums1):
        while amount < nums1[p1] + nums2[p2]:
            p2 -= 1
            if p2 < 0:
                # p1 became too large, we are done
                break
        else:
            # Found a valid p2 for the given p1
            sum_count += p2 + 1
            p1 += 1
            continue
        break

    return sum_count

def find_sum(k, nums1, nums2):

    # Sort both arrays, this runs in O(n * log(n))
    nums1.sort()
    nums2.sort()

    # Binary search through all sums, runs in O(n * log(max_sum))
    low = nums1[0] + nums2[0]
    high = nums1[-1] + nums2[-1]
    while low <= high:
        mid = (high + low) // 2
        sum_count = count_sums_of_at_most(mid, nums1, nums2)
        if sum_count >= k:
            high = mid - 1
        else:
            low = mid + 1

    return low

arr = [1, 4, 5, 6]
for k in range(1, 1 + len(arr) ** 2):
    print('sum', k, 'is', find_sum(k, arr, arr))

此打印:

sum 1 is 2
sum 2 is 5
sum 3 is 5
sum 4 is 6
sum 5 is 6
sum 6 is 7
sum 7 is 7
sum 8 is 8
sum 9 is 9
sum 10 is 9
sum 11 is 10
sum 12 is 10
sum 13 is 10
sum 14 is 11
sum 15 is 11
sum 16 is 12