Woodyiiiiiii / LeetCode

My private record of Leetcode solution

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Leetcode 2749. Minimum Operations to Make the Integer Zero

Woodyiiiiiii opened this issue · comments

2749. Minimum Operations to Make the Integer Zero

2749. Minimum Operations to Make the Integer Zero
O(1) Time || [C++/JAVA/Python] Beginner-friendly || Bit Manipulation
Linear Search On Answer (ft. Bit Count)

我觉得这道题目是最难的一道Q2的题目了。

比赛中我百思不得其解,我看到2的次方,就联想到了位运算,但每次操作都有一个num2阻拦,会影响到最后的位数,所以我就一直没明白如何解决。

我这里试图反推,从别人的solution中一步步模拟别人的思路,看能不能从中给我启发,能给我学到什么。

第一步,首先尽可能界定下边界范围。上面都说了比较看重位运算,不妨把这部分提出来,公式变成num1 - k * num2 = 2^i1 + 2^i2 + ... + 2 ^ ik。已知范围有num1、num2和i,右边是肯定大于0的,k也至少大于等于0,所以num2不能超过num1。

第二步,最难的一点——能不能确定答案的范围呢?假设有答案满足(不是-1),答案的上限是什么(下限肯定是0)? 还是回到公式num1 - k * num2,其等于2^i1 + 2^i2 + ... + 2 ^ ik,关注这个很特殊的二进制表示数。我们从已知出发,已知num1、num2,知道右边公式是一个long类型的数,求k。那么可以发现,其实方程num1 - k * num2是一个线性函数,只有两种图形,k是变量。所以k是单调变化的,递增/递减。然后关注右边式子,可以发现要满足有个k使得k个i,k 最大等于该数(可以分解成每个1),所以范围是(long)k <= (long)num1 - (long)k * num2,注意要转成long。如此就可以从小到大枚举k。

第三步,从第一步的公式可知,结合第二步得到的答案的范围,既然是肯定了上限,那就遍历所有可能的答案,算出差值long diff = (long) num1 - (long) k * (long) num2,然后看k到底能不能满足构造2^i1 + 2^i2 + ... + 2 ^ ik。怎么看满不满足呢?从i的范围出发,[0, 60],所以最小时k是等于该数的位数个数之和,也就是得到判断条件bits <= k

代码如下:

class Solution {
    public int makeTheIntegerZero(int num1, int num2) {
        if (num2 > num1) {
            return -1;
        }
        for (int k = 0; (long)k <= (long)num1 - (long)k * num2; k++) {
            long diff = (long) num1 - (long) k * (long) num2;
            long bits = Long.bitCount(diff);
            if (bits <= k) {
                return k;
            }
        }
        return -1;
    }
}