zoukankan      html  css  js  c++  java
  • leetcode1558题解【贪心】

    leetcode1558.得到目标数组的最少函数调用次数

    题目链接

    算法

    贪心

    时间复杂度O(nlogN)N为数组中最大的那个数。

    1.题意就是给定一个函数,该函数有两种功能,一种就是将数组中的所有数同乘以2,另一种就是将数组中的某个数加1。给定一个数组nums,让你将初始值全为0的数组arr通过调用给定的函数来变成nums。问最少调用次数。

    2.刚开始模拟了一番,但因为考虑的方法不对(至于哪里不对呢,就是一开始我就把数组的值都加1了一遍,然后再同乘以2,最后再一个个补1,这么做显然不利于减少次数。至于当时为啥这么想,估计是脑子抽了),最终无果。

    3.接下来步入正题,我们可以这么想。当初始值都为0时,我们可以使部分值首先加1(即最终要变成的较大的值),让它们首先乘以2,不断乘,乘到一定程度再处理。但这么做有个问题,让哪部分值先变成1呢?还有就是乘到哪种程度呢?

    这个地方的确是个难点,不太容易想。如果直接模拟的话不太容易。

    数组中谁乘2的次数最多,当然是目标值最大的那个数乘的次数最多,其他目标值较小的就相对来说乘的次数较少。我们可以贪心地让那些乘的次数较少的包含在乘的次数最多里面,至于它具体是怎么乘的,我们不用考虑太多,这就是贪心算法的好处。

    如何计算每个数最终乘的次数,我们可以分情况讨论:

    为了方便,我们可以从目标值向初始值变化。

    • 对于奇数,可以先让其变为偶数(变为偶数这个过程即减1,这个需要单独记录),然后再除2,每除一次就记录一次。

    • 对于偶数,就除2,每除一次就记录一次。可能除着除着就变成奇数了,比如250,这时候就执行上一步。

    最终,数组中的值就都变成0了。

    4.总之,这道题的基本思路就是求出目标数组中最大值变成0需要除2的次数,以及该数组中每个数需要减1的次数(什么时候减,就是为奇数的时候减),二者相加即为答案。

    C++代码

    class Solution {
    public:
        int minOperations(vector<int>& nums) {
            int len = nums.size();
            int res = 0;
            int mx = 0;     //记录乘以2的最大次数
            for(int i = 0; i < len; i++){
                int cnt = 0;
                while(nums[i]){
                    if(nums[i] % 2 == 1){
                        nums[i] -= 1;      //把它变成偶数
                        res++;
                    }
                    if(nums[i] > 0){
                        nums[i] /= 2;
                        ++cnt;
                    }
                }
                mx = max(mx, cnt);
            }
            res += mx;
            return res;
        }
    };
    

    思路来源

  • 相关阅读:
    Execl(2003)数据 导入 SQL Server(2005)
    访问远程MySQL
    国学堂—梁冬对话林曦
    男人对自己狠一点
    国学堂-梁冬对话王东岳
    国学堂—梁冬对话栗强
    内功
    学说话见识语言的力量
    一语道破中国千年潜规则——每天懂一点人情世故
    禅茶茶艺 (十二道)
  • 原文地址:https://www.cnblogs.com/KeepZ/p/13742122.html
Copyright © 2011-2022 走看看