本文已参与「新人创作礼」活动,一起开启掘金创作之路。
题目链接: leetcode.com/problems/nu…
1. 题目介绍(将一个数减成0需要几步)
Given an integer num, return the number of steps to reduce it to zero.
【Translate】: 给定一个整数num,返回将其减少为零的步骤数。
In one step, if the current number is even, you have to divide it by 2, otherwise, you have to subtract 1 from it.
【Translate】:怎么才算是一步,如果当前数是偶数,你必须除以2,否则(当前数是奇数),你必须减去1。
测试用例:
约束:
2. 题解
2.1 普通奇偶判断
由于题意说的很明确,也很简单,那么我们完全可以直接判断num的奇偶性然后对其进行相应的操作。
class Solution {
public int numberOfSteps(int num) {
int steps = 0;
while(num != 0){
if(num % 2 == 0){
num /= 2;
steps++;
}else{
num -= 1;
steps++;
}
}
return steps;
}
}
2.2 极致简洁的写法
这是Most Vote中AFeas1987的解法,第一部分,Integer.toBinaryString(num).length() - 1
获得数字- 1的二进制表示中的字符数。这等于x的最大值,满足2^x <= num,这个数表示num必须被2除的次数。第二部分,Integer.bitCount(num)
,返回num的“bit count”或"hamming weight",这是它的二进制表示中1的个数。这个数字表示在迭代方法中,在除法之前,我们会遇到一次减法运算的次数。但是我们可以看出性能比上我们的常规思路,并没有得到多少的提升。
public int numberOfSteps (int num) {
return Integer.toBinaryString(num).length() - 1 + Integer.bitCount(num);
}
2.3 递归思想
递归虽好,但是可不要贪杯噢!我们还是要根据不同的场景选择不同的办法。
我的理解是,递归有时候之所以能够展现出良好的性能,是因为通过限定调节,减少了执行次数,而不是单纯的递归就比循环快;正常来说,在相同的执行次数下,循环的效率要比递归的效率高,这在于递归自身的性质(递归每调用一次都要存一份当前function的副本,时间内存都消耗增大);但大家为什么这么热衷于使用递归来代替循环呢?我想可能是因为使用递归有时候能让代码更清晰简洁,而不是满屏的循环语句让人心烦。
public int numberOfSteps(int num) {
if(num != 0){
if(num%2 == 0)
return 1+numberOfSteps(num/2);
else
return 1+numberOfSteps(num-1);
}
return 0;
}
3. 可参考
[2] java源码Integer.bitCount算法原型和过程解析(附代码)
[3] java源码Integer类toBinaryString()方法探究
[4] 递归与循环相比时间优势的真正来源