昨天,在LeetCode刷题的时候,在Submission中看到一个执行用时很少的代码,里面用到了Integer.bitCount(i)方法,没明白是做什么的,看了注释后,才知道这个bitCount(i)方法是统计整形数字i对应的二进制中,有几个1,但是写法却让人迷惑,下面就来分析一下。
题目链接:1558. 得到目标数组的最少函数调用次数
先搜索了几篇文章看了下,大概意思渐渐理解了,做下记录。
先上一段代码,即bitCount()的原型:
public static int bitCount(int i) {
i = (i & 0x55555555) + ((i >>> 1) & 0x55555555);
i = (i & 0x33333333) + ((i >>> 2) & 0x33333333);
i = (i & 0x0f0f0f0f) + ((i >>> 4) & 0x0f0f0f0f);
i = (i & 0x00ff00ff) + ((i >>> 8) & 0x00ff00ff);
i = (i & 0x0000ffff) + ((i >>> 16) & 0x0000ffff);
return i;
}
十六进制 | 二进制 |
0x55555555 | 01010101010101010101010101010101 |
0x33333333 | 00110011001100110011001100110011 |
0x0f0f0f0f | 00001111000011110000111100001111 |
0x3f | 00000000000000000000000000111111 |
……
第五行,每次看二进制的32位,统计32位中1的个数,再放到原位置上。
此时,bitCount()的原型就能理解了。再看bitCount()的优化部分。
public static int bitCount(int i) {
// HD, Figure 5-2
i = i - ((i >>> 1) & 0x55555555);
i = (i & 0x33333333) + ((i >>> 2) & 0x33333333);
i = (i + (i >>> 4)) & 0x0f0f0f0f;
i = i + (i >>> 8);
i = i + (i >>> 16);
return i & 0x3f;
}
public static void main(String[] args) {
int i = 144358622;
System.out.println("i的十进制表示: " + Integer.toBinaryString(i));
i = i - ((i >>> 1) & 0x55555555);
System.out.println("每次看 2位,统计 2位里1的数量,放到原位置上:" + Integer.toBinaryString(i));
i = (i & 0x33333333) + ((i >>> 2) & 0x33333333);
System.out.println("每次看 4位,统计 4位里1的数量,放到原位置上:" + Integer.toBinaryString(i));
i = (i + (i >>> 4)) & 0x0f0f0f0f;
System.out.println("每次看 8位,统计 8位里1的数量,放到原位置上:" + Integer.toBinaryString(i));
i = i + (i >>> 8);
System.out.println("每次看16位,统计16位里1的数量,放到原位置上:" + Integer.toBinaryString(i));
i = i + (i >>> 16);
System.out.println("每次看32位,统计32位里1的数量,放到原位置上:" + Integer.toBinaryString(i));
i = i & 0x3f;
System.out.println("最终结果的二进制表示:" + Integer.toBinaryString(i));
}
注意,Integer.toBinaryString()会忽略前导0,分析的时候,需要手动添加,下面是我手动模拟一遍的数据。
00-00-10-00-10-01-10-10-10-11-11-00-11-01-11-10(原始数据)
00-00-01-00-01-01-01-01-01-10-10-00-10-01-10-01(每2位统计)
0000--0001--0010--0010--0011--0010--0011--0011 (每4位统计)
00000001----00000100----00000101----00000110 (每8位统计)
0000000100000101--------0000100100001011 (每16位统计)
00000001000001010000101000010000 (每32位统计)