剑指offer08-二进制中的一个数

208 阅读3分钟

二进制中的一个数

题目描述

输入一个整数,输出该数二进制表示中1的个数。其中负数用补码表示。
思路1
  • 把一个整数减去1,再和原整数做与运算,会把该整数最右边的1变成0.那么一个整数的二进制表示中有多少个1,就可以进行多少次这样的操作。
程序(java)
    /**
     * code1
     * 时间复杂度:
     */
public class Solution {
    public int NumberOf1(int n) {
    	int count=0;
    	while(n!=0) {
    		n=(n-1)&n;
    		count++;
    		}
    	return count;
    	}
}
思路2
  • 首先把n和0x80000000做与运算,判断n的最高位是不是1.接着把n左移一位,再和0x80000000做与运算......如此将n反复左移,直到整个整数n变成0为止。即此问题变为判断一个整数的最左边是不是1.
程序(java)
    /**
     * code2
     * 时间复杂度:O(n)
     */
public class Solution {
    public int NumberOf1(int n) {
    	int count=0;
    	while(n!=0) {
    		if((n&0x80000000)!=0) {
    			count++;
    		}
    		n=n<<1;
    		}
    	return count;
    	}
}
思路3
  • 首先把n和1做与运算,判断n的最低为是不是1.接着把1左移以为得到2,再和n做与运算,就能判断n的低次位是不是1。如此反复,每次都能判断n的其中一位是不是1.
程序(java)
    /**
     * code3
     * 时间复杂度:O(n)
     */
public class Solution {
public int NumberOf1(int n) {
	int flag=1;
	int count=0;
	while(flag!=0) {
		if((n&flag)!=0) {
			count++;
		}
		flag=flag<<1;
		}
	return count;
	}
}

补充(位运算)

  1. java里没有无符号(unsigned)整型。
  2. 位运算符
    No. 运算符 描述
    1 & 按位“与”
    2 | 按位“或”
    3 ^ 异或(相同为0,不同为1)
    4 ~ 取反
    5 << 左位移
    6 >> 右位移
    7 >>> 无符号右位移
  3. 左移位(<<)、右移位(>>)
    1). m<<n表示把m左移n位,在左移的时候,最左边的n位将被丢弃,同时在最右边补上n个0.
    0000 1010 << 2 = 0010 1000
    1000 1010 << 3 = 0101 0000
    
    2). m>>n表示把m右移n位,在右移的时候,最右边的n位将被丢弃。最左边位分两种情况:如果数字原先是一个正数,则右移之后在最左边补n个0;如果数字原先是负数,则右移之后在最左边补n个1.
    0000 1010 >> 2 = 0000 0010
    1000 1010 >> 3 = 1111 0001
    
    3). 右移位操作符(>>>)
    无论正负,都在高位插入0.
    0000 1010 >>> 2 = 0000 0010
    1000 1010 >>> 3 = 0001 0001
    
  4. 位运算的效率比乘除法及取余运算的效率要高很多。
  5. 十进制转二进制 负数转二进制:
    1)、取负数的绝对值的原码;
    2)、计算原码的反码;
    3)、对反码加一,获取补码