zoukankan      html  css  js  c++  java
  • [LeetCode 1558] Minimum Numbers of Function Calls to Make Target Array

    Your task is to form an integer array nums from an initial array of zeros arr that is the same size as nums.

    Return the minimum number of function calls to make nums from arr.

    The answer is guaranteed to fit in a 32-bit signed integer.

     

    Example 1:

    Input: nums = [1,5]
    Output: 5
    Explanation: Increment by 1 (second element): [0, 0] to get [0, 1] (1 operation).
    Double all the elements: [0, 1] -> [0, 2] -> [0, 4] (2 operations).
    Increment by 1 (both elements)  [0, 4] -> [1, 4] -> [1, 5] (2 operations).
    Total of operations: 1 + 2 + 2 = 5.
    

    Example 2:

    Input: nums = [2,2]
    Output: 3
    Explanation: Increment by 1 (both elements) [0, 0] -> [0, 1] -> [1, 1] (2 operations).
    Double all the elements: [1, 1] -> [2, 2] (1 operation).
    Total of operations: 2 + 1 = 3.
    

    Example 3:

    Input: nums = [4,2,5]
    Output: 6
    Explanation: (initial)[0,0,0] -> [1,0,0] -> [1,0,1] -> [2,0,2] -> [2,1,2] -> [4,2,4] -> [4,2,5](nums).
    

    Example 4:

    Input: nums = [3,2,2,4]
    Output: 7
    

    Example 5:

    Input: nums = [2,4,8,16]
    Output: 8
    

     

    Constraints:

    • 1 <= nums.length <= 10^5
    • 0 <= nums[i] <= 10^9

    For each operation, we can do one of the following:

    (1) pick an i and increment A[i] by 1;

    (2) multiply all the numbers in A by 2.

    Incorrect attempt during contest

    Key observations:

    1.  Obviously option 2 is always at least as good as option 1 toward reaching the final target array. So we should use the multipy option as many times as we can until we reach a state that further applying multiplication option would cause some numbers go over the intended target values. 

    2. To reach the final target, each position's number will have at least one option 1 operation: either to change 0 to 1 at the beginning or later time, or keep adding 1 to reach the final value after we can not use multiplication anymore. 

    3. The number of multiplications applied is determined by the max number in the target array. Why? Because for smaller target values, we can always keep them as 0s and only add 1 to the bigger target values then apply some * 2 operations, then add 1 to these smaller values and apply some more * 2 operations. The key here is 0 * 2 is still 0. In another word, all * 2 operations are shared among all numbers and we can freely choose the number of * 2 that makes a change. For smaller numbers we want to leave them as 0 for a while before making them 1 then start to multiply by 2.

    Incorrect algorithm: First we find the max value and use it to calculate how many * 2 we can have starting from value 1. Then iterate the target array and for each target value V, do this: starting from 1, keep * 2 until doing it one more time will cause the new value exceeds V, call this new value T. Then we'll need another V - T +1 operations. Before moving to the next value, add 1 to the final count as we must go from 0 to 1 first. 

    Consider this counter example: [1000], the correct answer should be 15, but my solution outputs 498! So what goes wrong here? Well, the way I tried to construct V is to start from 1, then keep multiplying by 2 until I can not anymore. Only by then I would consider the +1 operations, which is the difference between V and T. 512 * 2 > 1000, so I stopped at 512 by using one +1 and 9 mulitiplications. 1000 - 512 + 10 = 498. The right action should be as follows, using only 15 operations: 

    0 + 1 = 1

    1 * 2 = 2

    2 + 1 = 3

    3 * 2 = 6

    6 + 1 = 7

    7 * 2 = 14

    14 + 1 = 15

    15 * 2 = 30

    30 + 1 = 31

    31 * 2 = 62

    62 * 2 = 124

    124 + 1 = 125 

    125 * 2 = 250

    250 * 2 = 500

    500 * 2 = 1000

    So the problem is that we do not have to only use back to back * 2 and back to back +1, we can mix them together to reach a target value faster. As a result, instead of going forward from 0 to V, we should go backward from V to 0 as described in the correct algorithm below.

    class Solution {
        public int minOperations(int[] nums) {
            int maxV = 0;
            for(int v : nums) {
                maxV = Math.max(maxV, v);
            }
            int mul = 0;
            int p = 1;
            while(p < maxV) {
                p = p * 2;
                mul++;
            }
            if(p > maxV) {
                mul--;
                p = p / 2;
            }
            
            int ans = mul;        
            for(int v : nums) {
                int t = 1;
                while(t < v) {
                    t = t * 2;
                }
                if(t > v) {
                    t = t / 2;
                }
                //0 -> 1
                ans++;
                ans += (v - t);
            }
            return ans;
        }
    }

    Correct Algorithm

    Based on the above analysis, it is clear that the right algorithm is to check each target value backward, from V to 0. As long as V is > 0, we need some more operations: if V is odd, we must came from a smaller even value by adding 1 to it, so we use one +1 and V--; if V is even, it means we came from V / 2, so we use one * 2 and V = V / 2. When iterating each target value, we also keep track of the maximum multiplications needed, this is the total * 2 we need for getting to the entire target array. 

    class Solution {
        public int minOperations(int[] nums) {
            int inc = 0, mul = 0;
            for(int v : nums) {
                int currMul = 0;
                while(v > 0) {
                    if(v % 2 != 0) {
                        inc++;
                        v--;
                    }
                    else {
                        v /= 2;
                        currMul++;
                    }
                }
                mul = Math.max(mul, currMul);
            }
            return inc + mul;
        }
    }

    Related Problems

    [LeetCode 991] Broken Calculator

  • 相关阅读:
    pandas,对dataFrame中某一个列的数据进行处理
    pandas的简单使用
    pandas,读取或存储DataFrames的数据到mysql中
    pandas,pd.ExcelWriter保存结果到已存在的excel文件中
    用命令让vbox的虚拟硬盘文件转换成vmware的vmdk
    vbox磁盘空间如何扩容
    Linux ext3/ext4数据恢复
    VirtualBox安装64位系统
    ubuntu 12.04启用休眠
    美化你的GRUB,全面支持中文(菜单、提示、帮助)适用7.04-9.04
  • 原文地址:https://www.cnblogs.com/lz87/p/13548042.html
Copyright © 2011-2022 走看看