将数字变成 0 的操作次数
来源:力扣(LeetCode)题源链接
题目:给你一个非负整数 num ,请你返回将它变成 0 所需要的步数。 如果当前数字是偶数,你需要把它除以 2 ;否则,减去 1 。
小白尝试:
int numberOfSteps(int num){
int cnt=0;
while(num>0){
if(0==num%2) //当num为偶数时除以2
num=num/2;
else //当num为奇数时减1
num--;
cnt++; //操作步数count加一
}
return cnt;
}
这是最简单易懂的解决方法之一
可以注意到,上面的
if(0==num%2)
是常量0在左侧,这种代码风格习惯的好处在于可以避免双等号写成单等号,意外赋值,而导致程序的逻辑错误。比如不小心写成if(0=num%2)
,此时编译器就会报错,因为我们不能给常量0赋值。当然现代的一些IDE的代码审查工具也可以帮助检测出此类错误,这只是一种编程风格的选择
leetcode官方解答:
int numberOfSteps(int num) {
int ret = 0;
while (num) {
ret += (num > 1 ? 1 : 0) + (num & 0x01);
num >>= 1;
}
return ret;
}
(num > 1 ? 1 : 0)
这是一个(三目运算符)条件表达式,检查num是否大于1。若num>1,则ret+1;若num<=1,则不增加ret的值,直接进入下一步
(num & 0x01)
这是位与运算,用于判断num奇偶
。若num为奇数,则会返回1;若为偶数,则返回0;因此这一步假如num是奇数的话,ret+1
num >>= 1
这将num右移了一位。当num为奇数的话,结果为(num-1)/2;当num为偶数的话,则等价于num/2
由此,该函数的逻辑就是,
①先判断num>1?,是的话操作步数+1。因为只要num>1,无论奇偶,步数都会+1
②判断num是否为奇数?是奇数的话操作步数+1
③操作num
假设num=7,执行①②③之后,ret=2,num=3;
再执行①②③操作,ret=4,num=1;
再执行②③操作,ret=5, num=0;
再po个评论区大佬的解答:
递归解法
int numberOfSteps(int num) {
if(num==0){
return ;
}
step++;
if(num%2==0){
numberOfSteps(num/2);
}else {
numberOfSteps(num-1);
}
}
当然更简约一点可以这样:
int numberOfSteps(int num) {
if(num==0){
return ;
return (num%2==0 ? numberOfSteps(num/2):numberOfSteps(num-1)) +1;
}
假设我们调用numberOfSteps(15)
,过程如下:
- 15是奇数,所以调用
numberOfSteps(14)
然后加1。此时还未返回,继续递归。 - 14是偶数,所以调用
numberOfSteps(7)
然后加1。继续深入。 - 7是奇数,调用
numberOfSteps(6)
然后加1。 - 6是偶数,调用
numberOfSteps(3)
然后加1。 - 3是奇数,调用
numberOfSteps(2)
然后加1。 - 2是偶数,调用
numberOfSteps(1)
然后加1。 - 1是奇数,调用
numberOfSteps(0)
然后加1。 - 当num=0时,根据基础情况返回0。
从这最后一步(num=0时返回0),递归开始回溯,每回溯一层,就相当于给总的步数加1,因为它代表了到达那个状态需要的额外一步操作(无论是除以2还是减1)。所以,当从最底层(num=0)回溯到最初的调用(num=15)时,实际上每一步都为最终结果贡献了自己的“+1”,累计了从原始输入到0所需的总步数。
因此,虽然直接看最后一次基础递归调用返回了0,但这个0是一个触发点,让所有的递归调用能够开始回溯并累加它们各自计算的步数,从而最终得出原始num
减少到0所需的总步数。