📅  最后修改于: 2023-12-03 15:37:16.308000             🧑  作者: Mango
给定一个长度为 n 和 k 的数组 arr [],其中对于每对 i 和 j (1 <= i <j <= n),都有至少 k 个元素位于 arr [i] 和 arr [j] 之间。
求在数组中即可找到的不同对数目。
输入:
n = 5, k = 2
arr [] = {5, 1, 2, 7, 4}
输出:
6
最简单直观地思路是暴力法:枚举所有的 (i, j) 对,然后统计符合要求的对数。这种方法时间复杂度太高,无法通过此题。接着我们考虑优化。
将原数组快速排序。
用两个下标 l
和 r
分别指向排好序后的数组的最左侧和最右侧。同时,对于任意一个下标 i
,其之前(在 l
和它自身之间)必定有不少于 k
个数,之后(在它自身到 r
之间)也必定有不少于 k
个数。这个性质非常显然。
因为排好序后的数组是有序的,为了找到不同的对数,我们可以考虑双指针的方法。用两个下标 p
和 q
分别从 l
和 l+1
开始往 r
遍历。
如果当前区间 [arr[p], arr[q]]
的元素数不足 k
个,那么代表我们需要向右移动指针 q
来扩大这个区间。
如果当前区间 [arr[p], arr[q]]
的元素数超过或等于 k
个,那么代表我们可以增加
的对数。具体来说,我们可以从长度为 k
的区间 [arr[p], arr[p]+k-1]
中任取一点作为一对符合要求的元素对的一个元素,而对于另一个元素对应的区间,由于当前区间是包含上一个区间的,因此我们选取 [arr[p+1], arr[q]]
中所有满足要求的元素作为另一个元素。选完之后,p
和 q
分别向右移动一位继续考虑。
最终,我们找到了数组中所有的不同对数目,时间复杂度为 O(nlogn)
。
def count_pairs(n, k, arr):
# 步骤 1:将原数组排好序
arr.sort()
# 步骤 2:初始化指针 p 和 q
p, q = 0, 1
# 步骤 3:找到所有符合要求的元素对
res = 0
while p < n - 1:
# 步骤 4:如果元素数少于 k,则向右扩大区间
while q < n and arr[q] - arr[p] < k:
q += 1
# 步骤 5:如果元素数不少于 k,则统计对数
if q < n and arr[q] - arr[p] >= k:
# 取得可以选择的元素数
cnt = q - p - k + 2
res += cnt * (cnt - 1) // 2
p += 1
return res
# 示例测试
n = 5
k = 2
arr = [5, 1, 2, 7, 4]
print(count_pairs(n, k, arr)) # 6
返回结果为 6
,符合预期。