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

Posted lixycc

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了6392. 使数组所有元素变成 1 的最少操作次数相关的知识,希望对你有一定的参考价值。

题目链接:6392. 使数组所有元素变成 1 的最少操作次数

方法一:计算最短的gcd为1的子数组

解题思路

  • 本题目标:使得所有的数组元素都变为 \\(1\\),通过求相邻元素 \\(gcd\\) 将其赋值给一方的方式;
  • 思路:
    • 若想操作数最少,那么就是不为 \\(1\\) 的数 \\(x\\) 和 1 求 \\(gcd\\),即 \\(x = gcd(x, 1)\\),这样一次就可以将 \\(x\\) 变为 \\(1\\)
    • 因此现在至于要找最短的 \\(gcd\\)\\(1\\) 的子数组,先将其中一个数转换为 \\(1\\) ,然后将其他不等于 \\(1\\) 的元素通过一次操作变为 \\(1\\)
  • 特殊情况:
    • 数组整体的 \\(gcd\\) 不为 \\(1\\),说明不管怎么操作都不能出现 \\(1\\),那么一定不能变为 \\(1\\)
    • 数组中已经存在 \\(1\\),那么对于已经是 \\(1\\) 的元素就不需要多余操作。

代码

class Solution 
public:
    int minOperations(vector<int>& nums) 
        int cnt = 0, g = 0, n = nums.size();
        for (int i = 0; i < n; i ++ ) 
            if (nums[i] == 1) cnt ++ ;
            g = gcd(g, nums[i]);
        
        if (g != 1) return -1;
        if (cnt > 0) return n - cnt; // 特殊情况
        int mn = n;
        for (int i = 0; i < n; i ++ ) 
            g = nums[i], cnt = 1; // 暴力查找 gcd = 1 的最短子数组
            for (int j = i + 1; j < n; j ++ ) 
                g = gcd(g, nums[j]);
                cnt ++ ;
                if (g == 1) 
                    mn = min(mn, cnt);
                    break;
                
            
        
        return n + mn - 2;
    
;

复杂度分析

时间复杂度:\\(O(n^2)\\)
空间复杂度:\\(O(1)\\)

方法二:通过gcd性质优化

解题思路

通过迭代的方式计算子数组的 \\(gcd\\) 并进行去重优化(保持数组的连续性),注意 \\(g\\) 数组存储的元素含义。

class Solution 
public:
    int minOperations(vector<int>& nums) 
        int cnt = 0, res = 0, n = nums.size();
        for (auto &x : nums) 
            if (x == 1) cnt ++ ;
            res = gcd(res, x);
        
        if (res != 1) return -1;
        if (cnt > 0) return n - cnt;
        vector<pair<int, int>> g; // gcd, 相同的gcd的子数组最靠右边的左端点
        int mn = n;
        for (int i = 0; i < n; i ++ ) 
            g.emplace_back(nums[i], i); // 添加
            int j = 0;
            for (auto &p : g) 
                p.first = gcd(p.first, nums[i]); // 相当于求 [p.second, i] 的 gcd
                if (p.first == g[j].first)  // 说明出现相同的 gcd,那么将靠右的左端点复制到 g[j],跳过 p
                    g[j].second = p.second;
                 else  // 说明出现不相同的 gcd 那么将 P move 到 ++ j 的位置,弥补数组空缺
                    g[ ++ j ] = move(p);
                
            
            g.resize(j + 1);
            if (g[0].first == 1) mn = min(mn, i - g[0].second + 1); // 第一个元素的 gcd 值一定最小,因为其结果是从开始到当前位置所有元素的 gcd
        
        return n + mn - 2;
    
;

复杂度分析

时间复杂度:\\(O(nlogU)\\)\\(U = max(nums[0, n - 1])\\)
空间复杂度:\\(O(logU)\\)

462. 最少移动次数使数组元素相等 II

一、题目描述

给定一个非空整数数组,找到使所有数组元素相等所需的最小移动数,其中每次移动可将选定的一个元素加1或减1。 您可以假设数组的长度最多为10000。

示例 1:
输入:
[1,2,3]

输出:
2

说明:
只有两个动作是必要的(记得每一步仅可使其中一个元素加1或减1): 

[1,2,3]  =>  [2,2,3]  =>  [2,2,2]

二、解题

先将数组排序,双指针移动,头指针和尾指针,前后同时移动,走到中间,每一次的指针的指向的两个数值相减就是需要改变的次数。

class Solution 
    public int minMoves2(int[] nums) 
        //先排序
        Arrays.sort(nums);
        int l = 0,r = nums.length - 1;
        int move = 0;
        while(l<=r)
            move += nums[r] - nums[l];
            r--;
            l++;
        
        return move;
    

以上是关于6392. 使数组所有元素变成 1 的最少操作次数的主要内容,如果未能解决你的问题,请参考以下文章

453. 最小移动次数使数组元素相等(数学)

Leetcode 462.最少移动次数使数组元素相等

462. 最少移动次数使数组元素相等 II

LeetCode:最少移动次数使得数组元素相等||462

462 Minimum Moves to Equal Array Elements II 最少移动次数使数组元素相等 II

LeetCode 1775. 通过最少操作次数使数组的和相等