📅  最后修改于: 2023-12-03 14:57:31.213000             🧑  作者: Mango
这个问题可以通过暴力枚举数组中所有可能的数对来解决,但是时间复杂度为 $O(n^2)$,对于数据量较大的情况可能会超时。
下面介绍一种时间复杂度为 $O(n\log n)$ 的解法。
我们先来解决一个比较简单的问题:如何快速计算数组中所有数对的 LCM 和 min 值。
设 $LCM(i,j)$ 表示数组中 $i$ 和 $j$ 的 LCM 值,$min(i,j)$ 表示数组中 $i$ 和 $j$ 的最小值,那么有:
$$LCM(i,j) = \frac{arr[i] \times arr[j]}{gcd(arr[i], arr[j])}$$
$$min(i,j) = \min{arr[i], arr[j]}$$
其中 $gcd$ 表示最大公约数,可以使用欧几里得算法来计算,时间复杂度为 $O(\log n)$。
接着我们考虑如何利用以上方法求解本题。注意到对于一个数对 $(i,j)$,如果满足条件 LCM($i,j$) > min($i,j$),那么意味着 $\frac{arr[i]}{gcd(arr[i], arr[j])} \neq \frac{arr[j]}{gcd(arr[i], arr[j])}$,否则它们的 LCM 和 min 值相同。因此我们可以枚举一个数 $i$,然后找到所有满足上述条件的 $j$,这些 $j$ 的下标就构成了一些对。我们可以使用一个哈希表来存储每个值出现的下标,然后在查找时可以快速定位。
下面是 Python 代码实现:
from math import gcd
def count_pairs(arr):
n = len(arr)
count = 0
hash_table = {} # 存储每个值出现的下标
for i in range(n):
# 枚举数对 (i,j)
for j in range(i+1, n):
# 计算 LCM 和 min 值
lcm = arr[i] * arr[j] // gcd(arr[i], arr[j])
min_val = min(arr[i], arr[j])
# 检查是否满足条件
if lcm > min_val:
count += 1
# 将 i 和 j 加入哈希表
if arr[i] in hash_table:
hash_table[arr[i]].append(i)
else:
hash_table[arr[i]] = [i]
if arr[j] in hash_table:
hash_table[arr[j]].append(j)
else:
hash_table[arr[j]] = [j]
# 枚举每个数 i,查找符合条件的 j
for i in range(n):
for j in hash_table:
if j == arr[i]:
continue
lcm = arr[i] * j // gcd(arr[i], j)
if lcm > arr[i]:
# 计算在哈希表中出现的次数
count += len([x for x in hash_table[j] if x > i])
return count
时间复杂度为 $O(n\log n)$。