397. 整数替换【medium】

给定一个正整数 n ,你可以做如下操作:

  如果 n 是偶数,则用 n / 2替换 n 。
  如果 n 是奇数,则可以用 n + 1或n - 1替换 n 。
  n 变为 1 所需的最小替换次数是多少?

示例 1:

输入:n = 8
输出:3
解释:8 -> 4 -> 2 -> 1

示例 2: 

输入:n = 7
输出:4
解释:7 -> 8 -> 4 -> 2 -> 1
或 7 -> 6 -> 3 -> 2 -> 1

示例 3: 

输入:n = 4
输出:2

提示:

1 <= n <= 2的31次方-1

当时第一反应是动态规划直接dp即可,但看一下n的数据范围,2的31次方-1,dp很显然会超时和爆内存。

仔细一想,二进制可解,这题我们拿357来举例

357 ->101100101
    101100100
       10110010
        1011001
        1011000
         101100
          10110
           1011
           1100
            110
             11
             10
              1
1   ->000000001
很显然 
二进制最后一位为0,说明是偶数,我们直接/2,也就是向右移动一位
二进制最后一位为1,说明是奇数,这时候我们看倒数第二位,如果倒数第二位是0,那就是01结尾,那进行-1可以变成00
                                              如果倒数第二位是1,那就是11结尾,那进行+1可以变成100

11->100->10->1 3次
11->10->1 2次
看上去应该下面这条-1的式子更快,那看看下面这个例子      1011->1100->110->11->1 1011->1010->1000->100->10->1 显然上面会快,如果最后两位二进制都为1时,且前面没有多的二进制数时,-1操作才会比+1快,否则+1都会比-1快                     3是一种特殊情况  由于接下来由于解说复杂,不予说明(人菜不知道如何用文字解释 如果还想不明白可以自己可以拿不同的二进制数进行模拟 得出结论:如果是二进制结尾是11,且二进制长度大于3时 n = (n +1)/2; 像上面这样写就又错了 因为如果n的二进制为极限情况下为11111111....,进行+1操作再/2会因为超过int的范围而出错 正确写法:n = n / 2 + 1;

以下为AC代码

class Solution {
public:
    int integerReplacement(int n) {
        int ans=0;
        while (n != 1) {
            if (n % 2 == 0) {
                n = n >> 1;
                ans++;
            }
            else {
                if (n & 1 == 1 && n >> 1 & 1 == 1&&n>3) {//判断3的特殊情况
                    n = n /2+1;//注意int的范围
                    ans+=2;
                }
                else {
                    n = n - 1;
                    ans++;
                }
            }
        }
        return ans;
    }
};

 

posted @ 2021-11-21 00:19  夜灯长明  阅读(57)  评论(0编辑  收藏  举报