📌  相关文章
📜  将数组拆分为最小数量的子数组,其第一个和最后一个元素的 GCD 超过 1(1)

📅  最后修改于: 2023-12-03 15:25:19.773000             🧑  作者: Mango

将数组拆分为最小数量的子数组,子数组的首尾元素 GCD 超过 1

题目描述:给定一个整数数组,将其拆分为最小数量的子数组,满足每个子数组的最大公约数(GCD)大于 1,并返回子数组的数量。

思路

从题目中可以看出,要求子数组的最大公约数大于 1。因此,我们可以采用动态规划的方法。我们定义 $dp[i]$ 表示从 0 到 i 的子数组最少可以被拆分成几个符合要求的子数组。

对于第 i 个元素,我们可以选择将其与前面的元素一起组成一个新的子数组,也可以选择以它作为子数组的开头,继续往后搜索。

因为子数组的最大公约数为所有元素的最大公约数,所以我们可以利用辗转相除法求出以第 i 个元素结尾的子数组的最大公约数,即 $gcd(nums[j], nums[j+1], ..., nums[i])$,其中 $j \leq i$。

因此,我们可以得到状态转移方程:

$$dp[i]=\min\limits_{j=0}^{i-1}\big{dp[i], dp[j-1]+1}\quad (gcd(nums[j], nums[j+1], ..., nums[i]) \gt 1)$$

初始状态为 $dp[0]=1$,表示只有一个元素,无法拆分成符合要求的子数组。

最终答案为 $dp[n-1]$,其中 $n$ 表示数组的长度。

代码实现(Python)
def splitArray(nums: List[int]) -> int:
    n = len(nums)
    dp = [float('inf')] * n
    for i in range(n):
        for j in range(i+1):
            if gcd(nums[j:i+1]) > 1:
                if j==0:
                    dp[i] = 1
                else:
                    dp[i] = min(dp[i], dp[j-1]+1)
    return dp[n-1]
复杂度分析

时间复杂度:$O(n^2 \log m)$,其中 $n$ 表示数组的长度,$m$ 表示数组中的元素的最大值。计算每个子数组的最大公约数的时间复杂度为 $O(k\log m)$,其中 $k$ 表示子数组的长度。

空间复杂度:$O(n)$,用于存储状态数组 $dp$。