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; } };