【Leetcode】1611. Minimum One Bit Operations to Make Integers Zero(配数学证明)

题目地址:

https://leetcode.com/problems/minimum-one-bit-operations-to-make-integers-zero/

给定一个正整数 n n n,将其视为二进制数。允许进行两种操作:
1、将其最低位取反;
2、如果左起第 i i i位是 1 1 1,并且第 i − 1 i-1 i1位一直到第 0 0 0位都是 0 0 0,那就可以将第 i + 1 i+1 i+1位取反。
问要将其变为 0 0 0至少需要多少步。

首先,对于任意 n n n,它一定要先变成形如 1100...0 1100...0 1100...0的数,才能继续变为 0 0 0。这是因为要将 n n n变为 0 0 0,必须其中某一步是将最高位变为 0 0 0,而最高位变为 0 0 0必须要得到形如 1100...0 1100...0 1100...0的数才能做。我们来证明两个命题:

1、对于 n = 2 k n=2^k n=2k来说,至少需要 2 k + 1 − 1 2^{k+1}-1 2k+11步。
数学归纳法:当 k = 0 k=0 k=0时显然。假设对于 k − 1 k-1 k1的情况上述命题也正确,对于 k k k的情况,由于 10...0 10...0 10...0先要变成 110...0 110...0 110...0,对于任意的能把 10...0 10...0 10...0变成 110...0 110...0 110...0的最短的操作序列,都不会改动最高位的 1 1 1(如果改变了的话,说明中途已经到了 110...0 110...0 110...0了,与最短矛盾),所以把 10...0 10...0 10...0变成 110...0 110...0 110...0的最短的操作序列其实就是把 0 0 0变为 10...0 10...0 10...0的操作序列(即只考虑除了最高位 1 1 1的剩余数字)。而题目的两个操作实际上是在做异或运算,这个运算是可逆的,所以把 0 0 0变为 10...0 10...0 10...0的最短操作序列的逆序就是把 10...0 10...0 10...0变为 0 0 0的最短操作序列,从而根据归纳假设,其有 2 k − 1 2^k-1 2k1步,接着 110...0 110...0 110...0变成 10...0 10...0 10...0需要 1 1 1步,然后再根据归纳假设,其经过 2 k − 1 2^k-1 2k1步变为 0 0 0,所以总共步数就是 2 k − 1 + 2 k = 2 k + 1 − 1 2^k-1+2^k=2^{k+1}-1 2k1+2k=2k+11步。由数学归纳法,命题对于任意 k k k都对。
2、将 n → x n\to x nx的最少步数等于 n ∧ x → x ∧ x = 0 n\wedge x\to x\wedge x=0 nxxx=0的最少步数,这一点由异或运算满足结合律显然成立(左边同时做异或即可)。

我们回到原问题,设 f ( n ) f(n) f(n)是答案。对于 n n n而言, n → 110...0 n\to 110...0 n110...0需要的步数就等于 n ∧ 110...0 → 110...0 ∧ 110...0 = 0 n\wedge 110...0\to 110...0\wedge 110...0=0 n110...0110...0110...0=0的步数,我们取 110...0 110...0 110...0是能将 n n n的最高位 1 1 1通过异或消掉的数,令 k k k是小于等于 n n n的最大的 2 2 2的幂(例如 n = 10 n=10 n=10的时候 k = 2 3 = 8 k=2^3=8 k=23=8 n = 17 n=17 n=17的时候 k = 2 4 = 16 k=2^4=16 k=24=16),那么显然 k + k / 2 k+k/2 k+k/2就是形如 110...0 110...0 110...0并且能将 n n n的最高位 1 1 1消掉的数。所以有 f ( n ) = f ( n ∧ 110...0 ) + 1 + k − 1 = f ( n ∧ 110...0 ) + k f(n)=f(n\wedge 110...0)+1+k-1=f(n\wedge 110...0)+k f(n)=f(n110...0)+1+k1=f(n110...0)+k只需要直接DFS就行了。因为每次参数的最高位都会被消掉,所以位数一定会越变越少,时间复杂度就是 O ( log ⁡ n ) O(\log n) O(logn)。代码如下:

public class Solution {
    public int minimumOneBitOperations(int n) {
        return dfs(n);
    }
    
    private int dfs(int n) {
        if (n == 0) {
            return 0;
        }
        
        int k = 1;
        while (k << 1 <= n) {
            k <<= 1;
        }
        
        return dfs(k ^ (k >> 1) ^ n) + k;
    }
}

时空复杂度 O ( log ⁡ n ) O(\log n) O(logn)

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值