📅  最后修改于: 2023-12-03 14:55:23.120000             🧑  作者: Mango
在一个给定的整数数组中,找到长度至少为2的子数组,使得该子数组中所有数字的最大公因数(GCD)最大。返回该子数组的长度。
本题要求找到一个最长的子数组,使得该子数组的所有数字的最大公因数(GCD)最大。显然,最大公因数越大,这个子数组中的数字间的约束就越强,需要满足的条件也就更多,因此相对来说只可能存在更少的可能性,因而我们可以尝试利用这一点对算法进行优化。
具体来说,我们可以通过将数组中的数字按照它们的最大公因数进行分组,将具有相同最大公因数的数字聚合在一起,进一步缩小搜索空间。然后我们对于每个最大公因数下的数字集合,求出其中所有数字的 GCD,不难发现,该集合的 GCD 必定是这个最大公因数的倍数,因此我们只需要逐个枚举这个最大公因数的所有因数,找到集合中包含这个因数的最长的连续子数组即可。
具体的实现,可以先使用一个哈希表将数字按照它们的最大公因数分组,然后针对每个分组,使用一个数组存储它们的 GCD,再枚举每个最大公因数的因数,通过双指针法在集合中找到满足条件的最长子数组。
class Solution:
def maxGCD(self, nums: List[int]) -> int:
# 将数字按照 GCD 分组,并求出它们的 GCD
groups = collections.defaultdict(list)
for num in nums:
for i in range(1, int(num ** 0.5) + 1):
if num % i == 0:
groups[i].append(num)
if i != num // i:
groups[num // i].append(num)
gcds = [0] * len(groups)
for i, (factor, group) in enumerate(groups.items()):
gcds[i] = functools.reduce(math.gcd, group)
# 对于每个最大公因数,找到包含它的最长连续子数组
res = 0
for i in range(len(groups)):
factor = list(groups.keys())[i]
for j in range(i, len(groups)):
if list(groups.keys())[j] % factor == 0:
l, r = 0, 0
while r < len(groups[j]):
while r < len(groups[j]) and gcds[j] % factor == 0:
r += 1
res = max(res, r - l)
while l < r and gcds[j] % factor != 0:
l += 1
return res if res >= 2 else 0
最初的分组操作需要对每个数字分别求其所有因数,因此时间复杂度为 $O(n\sqrt{n})$;求出每个分组的 GCD,以及枚举最大公因数和双指针操作,都只需线性遍历一遍数组,因此时间复杂度为 $O(n)$。因此,算法的总时间复杂度为 $O(n\sqrt{n})$。
空间复杂度上,哈希表与分组数组各需要 $O(n)$ 的空间,GCD 数组需要 $O(\sqrt{n})$ 的空间。因此,算法的总空间复杂度为 $O(n+\sqrt{n})$,可以过测试数据。