leetcode- Number of 1 bits, power of two, power of three

来源:互联网 发布:java安装进度条不动 编辑:程序博客网 时间:2024/05/20 18:17

Question
1、Write a function that takes an unsigned integer and returns the number of ’1’ bits it has (also known as the Hamming weight).

For example, the 32-bit integer ’11’ has binary representation 00000000000000000000000000001011, so the function should return 3.

2、Given an integer, write a function to determine if it is a power of two.

3、
Given an integer, write a function to determine if it is a power of three.

Follow up:
Could you do it without using any loop / recursion?

知识点:
1、首先明确几个概念
Java中存储的数据是有符号的,而且用8byte来表示。如果输入的数超过范围,则不能在java中表示
2、
(1)overflow问题
我最开始的想法是用输入的数字不断除以2获得余数,然后所有的余数按照从后往前的顺序就可以得到其二进制。然后计算其中1的个数。
但是如果第一位是1的话,java存储的数据又是有符号的数据,会出现问题。
(2)移位问题
右移位分为无符号移位(>>>)和有符号移位(>>)
(3)符号运算先后顺序问题
注意,当使用了很多符号,但是不确定先后顺序的时候,记得加上括号。
同时:注意有些符号比如>=写成 > =就不对了
3、
精度问题:
(1)float和double的精度:
a 内存结构
float和double的范围是由指数的位数来决定的。
float的指数位有8位,而double的指数位有11位,分布如下:
float:1bit(符号位) 8bits(指数位) 23bits(尾数位)
double:1bit(符号位) 11bits(指数位) 52bits(尾数位)

于是,float的指数范围为-128~+127,而double的指数范围为-1024~+1023,并且指数位是按补码的形式来划分的。

其中负指数决定了浮点数所能表达的绝对值最小的非零数;而正指数决定了浮点数所能表达的绝对值最大的数,也即决定了浮点数的取值范围。

float的范围为-2^128 ~ +2^127,也即-3.40E+38 ~ +3.40E+38;double的范围为-2^1024 ~ +2^1023,也即-1.79E+308 ~ +1.79E+308。

b 、精度
float和double的精度是由尾数的位数来决定的。浮点数在内存中是按科学计数法来存储的,其整数部分始终是一个隐含着的“1”,由于它是不变的,故不能对精度造成影响。

float:2^23 = 8388608,一共七位,由于最左为1的一位省略了,这意味着最多能表示8位数: 2*8388608 = 16777216 。有8位有效数字,但绝对能保证的为7位,也即 float的精度为7~8位有效数字 ;

double:2^52 = 4503599627370496,一共16位,同理, double的精度为16~17位

之所以不能用f1==f2来判断两个数相等,是因为虽然f1和f2在可能是两个不同的数字,但是受到浮点数表示精度的限制,有可能会错误的判断两个数相等!
由于精度问题,double/float比较相等也不能直接使用==,但是比较大小可以用<、 >号

举例:double result = 1.0 - 0.9;
result:0.09999999999999998
float和double类型主要是为了科学计算和工程计算而设计的。他们执行二进制浮点运算,这是为了在广泛的数字范围上提供较为精确的快速近似计算而精心设计的。然而,它们并没有提供完全精确的结果,所以我们不应该用于精确计算的场合。float和double类型尤其不适合用于货币运算,因为要让一个float或double精确的表示0.1或者10的任何其他负数次方值是不可能的(其实道理很简单,十进制系统中不能准确表示出1/3。同样二进制系统也无法准确表示1/10,只能准备表达出1/(2^n)。

(2)解决精度问题:
普通的计算最好使用BigDecimal类,这个类可以非常精确的计算出结果,而且你可以完全控制精度,不用额外其他操作,而且与基本类型转换都非常方便。

三、Solution
1、

public class Solution {    public boolean isPowerOfTwo(int n) {        if (n < 0) return false;        int result = 0;        while (n != 0){            result += n & 1;            n = n >>> 1;        }        if(result == 1) return true;        else return false;    }}

再给出另一种方法:
思路
n = 0x1101 n-1 = 0x1100 n&(n - 1) = 0x1100
n = 0x1100 n-1 = 0x1010 n&(n - 1) = 0x1000
n = 0x1000 n-1 = 0x0111 n&(n - 1) = 0x0
可以看出n&(n-1)可以消除二进制表示中最后一个1,经过多次这样的循环,可以得到n中1的个数,代码如下:

public class Solution {    public boolean isPowerOfTwo(int n) {        if (n < 0) return false;        int result = 0;        while(0 != n)        {            n = n&(n - 1);            result++;        }        return result;    }    }  }

2、两种思路
(1)一种判断:该数的二进制表示法是不是只有一个1(注意,既然是2的power,那么一定是正数)
(2)另一种,对该数求对数得到m,然后求2^m,观察得到的数和输入的数是否相等,如果相等就是2的power,不相等则不是。(这种方法比前一种方法更好扩展,可以扩展到求一个数是不是n的power)

3、同2(2)方法

  public boolean isPowerOfThree(int n) {        if(n <= 0) return false;        return Math.pow(3,Math.round(Math.log(n)/Math.log(3))) == n;    }
0 0
原创粉丝点击