你是一个专业的小偷,计划偷窃沿街的房屋。每间房内都藏有一定的现金,影响你偷窃的唯一制约因素就是相邻的房屋装有相互连通的防盗系统,如果两间相邻的房屋在同一晚上被小偷闯入,系统会自动报警

给定一个代表每个房屋存放金额的非负整数数组,计算你在不触动警报装置的情况下,能够偷窃到的最高金额。

示例 1:

输入: [1,2,3,1]
输出: 4
解释: 偷窃 1 号房屋 (金额 = 1) ,然后偷窃 3 号房屋 (金额 = 3)。
     偷窃到的最高金额 = 1 + 3 = 4 。

示例 2:

输入: [2,7,9,3,1]
输出: 12
解释: 偷窃 1 号房屋 (金额 = 2), 偷窃 3 号房屋 (金额 = 9),接着偷窃 5 号房屋 (金额 = 1)。
     偷窃到的最高金额 = 2 + 9 + 1 = 12 。

上期的问题是:151,位1的个数

1public int hammingWeight(int n) {
2    return n == 0 ? 0 : 1 + hammingWeight(n & (n - 1));
3}

最简单的一种方式,n&(n-1)会消去二进制中最右端的1,通过递归运算,直到n等于0为止。还可以改为非递归的方式

1public int hammingWeight(int n) {
2    int total = 0;
3    while (n != 0) {
4        n = n & (n - 1);
5        total++;
6    }
7    return total;
8}

上面两种方式计算的原理都是一样的,都是不停的消去二进制中最右端的1。再来看一种写法

1 public int hammingWeight(int n) {
2     int total=0;
3     while(n!=0){
4         total+=n&1;
5         n=n>>>1;
6     }
7     return total;
8 }

这种方式更简单。在Integer这个类中也有计算二进制1的个数的,看下代码

1public static int hammingWeight(int i) {
2    // HD, Figure 5-2
3    i = i - ((i >>> 1) & 0x55555555);
4    i = (i & 0x33333333) + ((i >>> 2) & 0x33333333);
5    i = (i + (i >>> 4)) & 0x0f0f0f0f;
6    i = i + (i >>> 8);
7    i = i + (i >>> 16);
8    return i & 0x3f;
9}

这个计算的时候会用自己的位来存储,其实我感觉上面代码最经典的就是第3行,i = i - ((i >>> 1) & 0x55555555);他是每两位两位计算1的个数,然后再存储在这两位数中,然后后面的在每4位,8位……。如果看不明白我们还可以换种写法

1 public int hammingWeight(int n) {
2     n = ((n & 0xaaaaaaaa) >>> 1) + (n & 0x55555555);
3     n = ((n & 0xcccccccc) >>> 2) + (n & 0x33333333);
4     n = (((n & 0xf0f0f0f0) >>> 4) + (n & 0x0f0f0f0f)) & 0x0f0f0f0f;
5     n = (((n & 0xff00ff00) >>> 8) + (n & 0x00ff00ff)) & 0x00ff00ff;
6     n = n + (n >>> 16);
7     return n & 63;
8 }

这样就很明了了,不过看起来要比上面代码啰嗦些。如果对二进制了解不是很多的话,基本上看懂也很难,如果把上面的16进制全部转化为2进制就非常容易看懂了,

0xaaaaaaaa转化为二进制是10101010 10101010 10101010 10101010 

0x55555555转化为二进制是01010101 01010101 01010101 01010101

0xcccccccc转化为二进制是11001100 11001100 11001100 11001100

0x33333333转化为二进制是00110011 00110011 00110011 00110011