📌  相关文章
📜  与数组相距至少 K 距离的对的最小总和(1)

📅  最后修改于: 2023-12-03 14:48:52.087000             🧑  作者: Mango

与数组相距至少 K 距离的对的最小总和

问题描述

给定两个非空数组 nums1 和 nums2,其中长度分别为 n1 和 n2。数组下标从 0 开始。

数组 nums1 和 nums2 中的元素均为非负整数。

在初始时,需选出两个下标 i 和 j,其中 i 属于 nums1,j 属于 nums2,使得它们与数组相距的距离至少为 k。

距离是指两个下标之间的差的绝对值。

找出使得它们之间的差的绝对值之和最小的 k 对下标,并返回这些下标对以及它们的差的绝对值之和。

解决方案

这是一道贪心算法的题目。首先将两个数组分别排序。然后我们可以考虑数学上的方法,来减少计算量。

令 x 为 nums1 中的下标, y 为 nums2 中的下标,则有:

差的绝对值 = abs(nums1[x] - nums2[y])

显然,如果 nums1[x] > nums2[y],则若 nums1[x+1] < nums2[y],即 nums1 中下标为 x+1 的元素比 nums2 中下标为 y 的元素小,那么下标为 (x+1, y) 的差的绝对值必然比 (x, y) 的小,因此可以直接跳过比较小的 nums1 中的元素。同理,如果 nums1[x] < nums2[y],则也可直接跳过 nums2 中比 nums2[y] 小的元素。

那么我们可以首先用堆将两个数组的前 k 个元素进行排序,然后每次取出差的绝对值最小的元素,若 nums1 中的元素较小,则加入 nums1 的下一个元素,否则加入 nums2 的下一个元素。最后返回所选择的下标对和差的绝对值之和即可。

代码:

import heapq

def kSmallestPairs(nums1, nums2, k):
    heap = [(nums1[0] + nums2[0], 0, 0)]
    res = []
    while heap and len(res) < k:
        _, i, j = heapq.heappop(heap)
        res.append((nums1[i], nums2[j]))
        if i < len(nums1) - 1:
            heapq.heappush(heap, (nums1[i+1] + nums2[j], i+1, j))
        if i == 0 and j < len(nums2) - 1:
            heapq.heappush(heap, (nums1[i] + nums2[j+1], i, j+1))
    return [(x, y, abs(x-y)) for x, y in res], sum(abs(x-y) for x, y, _ in res)
总结

本题解采用了数学方法,在排序结束之后可以大幅度地减少比较的次数。由于要求的是差的绝对值之和最小,因此贪心地每次选择差的绝对值最小的元素即可。

时间复杂度为 O(klogk)。