📅  最后修改于: 2023-12-03 15:07:06.417000             🧑  作者: Mango
这个问题的主要目标是从一组整数中找到最大可能 GCD 为 k 的子序列。
一般情况下,求 GCD 是一个O(N) 的操作,那么我们可以考虑使用某种方法将复杂度降下来。根据定义 GCD 的性质,我们可以把 k 取公因数,然后把原序列的每个数都除以这个公因数,那么我们可以采用欧几里得算法递归求出这个序列的最大公约数,然后再乘回去即可求出原序列 GCD 为 k 的序列。
我们可以使用动态规划去求解,定义状态 dp[i][j] 表示下标从 1 开始的前 i 个元素中最大公约数为 j 的最长子序列长度。
显然,在求解 dp[i][j] 时,我们需要枚举前一个状态 dp[i-1][k] 的所有可能值,然后递归求解 dp[i][gcd(j, k)]。最终的答案为所有 dp[n][k] 中的最大值。
def GCD(a, b):
if(b==0): return a
return GCD(b,a%b)
def findMaxSubsequence(n, k, a):
a = [x // k for x in a]
MAX = max(a)
dp = [[0]*(MAX+1) for _ in range(n+1)]
for i in range(1, n+1):
for j in range(1, MAX+1):
for k in range(i):
if GCD(a[i-1], a[k]) == j:
dp[i][j] = max(dp[i][j], dp[k][j]+1)
# 初值就是1,不需要上面的循环
if GCD(a[i-1], k) == 1:
dp[i][1] = max(dp[i][1], 1)
res = max(dp[n])
return res
上述代码采用了传统的动态规划方式,时间复杂度是 O(n^3) 的,我们可以利用欧几里得的思想,用辗转相除法进行迭代求解,时间复杂度可以优化到 O(n^2*log(max(a)))。下面是修改后的代码:
def GCD(a, b):
if(b==0): return a
return GCD(b,a%b)
def findMaxSubsequence(n, k, a):
a = [x // k for x in a]
MAX = max(a)
dp = [[0]*(MAX+1) for _ in range(n+1)]
for i in range(1, n+1):
for j in range(1, MAX+1):
for k in range(j, MAX+1, j):
if dp[i-1][k]:
dp[i][j] = max(dp[i][j], dp[i-1][k] + (GCD(a[i-1], j) == k))
if GCD(a[i-1], k) == 1:
dp[i][1] = max(dp[i][1], 1)
res = max(dp[n])
return res
这个问题是一个经典的动态规划问题,可以使用传统的DP思想解决。同时也可以用辗转相除的思想和网上的一些博客提供的一些方法进行优化。在解决此类问题时,我们可以按照以下步骤进行: