我给了具有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、4、10],我们有
2 5 5 8 11 11 14 14 20
问题在于将4 + 4的和放置在哪里,这取决于1 + 10> 4 + 4,其他和具有固定的位置,因为第二个元素+ last将始终大于last + first(如果我们在升序)。
答案 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
答案 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