【Leetcode】2654. 使数组所有元素变成 1 的最少操作次数——1929

题目

2654. 使数组所有元素变成 1 的最少操作次数

给你一个下标从0开始的整数数组 nums 。你可以对数组执行以下操作任意次:

选择一个满足 0 <= i < n - 1 的下标 i ,将 nums[i] 或者 nums[i+1] 两者之一替换成它们的最大公约数。
请你返回使数组nums中所有元素都等于 1 的最少操作次数。如果无法让数组全部变成1,请你返回-1

两个正整数的最大公约数指的是能整除这两个数的最大正整数。

思路

最大公约数

首先,对于两个数字的最大公约数,可以使用gcd算法,可以在常数时间内求解两个数字的最大公约数。

解决问题的思路

如果是想要所有的数字都变为1,那么首先就是将某个数字变为1,之后利用1与其他正整数的最大公约数一定是1的结论,可以将这个1蔓延到其他所有的位置。

另一方面,根据数学方面的知识,对于同一组数据而言,增加数字,其最大公约数只会越来越小。

思路的视线

如果我们首先对某个位置进行了公约数的计算之后替换了其中之一的数字,之后将其他的位置通过公约数的计算得到了1,之后将这个1进行蔓延到其他非1的位置,那么这个操作是没有意义的。

因此我们要做的就是从数组中选取某一连续的片段,其最大公约数为1。

特殊情况

当然,如果数组中已经存在了1,那么只需要直接蔓延即可。
如果数组中所有元素的最大公约数都为非1,那么表明他们无论如何都不能通过最大公约数的求解得到1

鉴于本题目的数据范围较小,且公约数不存在逆运算,因此不能通过滑动窗口进行计算,因此直接使用两层循环暴力破解方式求解即可。

class Solution:
    def minOperations(self, nums: List[int]) -> int:
        n = len(nums)
        cnt1 = sum(x == 1 for x in nums)
        if cnt1:
            return n - cnt1

        ans = +inf
        for i in range(n):
            cur = nums[i]
            for j in range(i,n):
                cur = gcd(cur,nums[j])
                if cur==1:
                    ans = min(ans,j-i)
                    break
        return ans+(n-1) if ans!=+inf else -1
posted @ 2024-10-20 21:07  TICSMC  阅读(29)  评论(0)    收藏  举报