Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

n & (n - 1) 的含义 #80

Open
Shellbye opened this issue Nov 11, 2019 · 0 comments
Open

n & (n - 1) 的含义 #80

Shellbye opened this issue Nov 11, 2019 · 0 comments

Comments

@Shellbye
Copy link
Owner

Shellbye commented Nov 11, 2019

这真可以说是一个老朋友了,在不同的地方见过了好多次,只是我每次看见它,都得查一查它到底是什么意思,而且每次它的含义都还有点不同。这次看《剑指 offer》,作者讲解的比较清楚,所以我在这里顺便记录一下。

先看 n - 1

如果整数不为 0 ,则它的二进制表示中,至少有一位得是 1 。假设这个 1 位于最右侧,那么减去 1 之后,最右侧就变成了 0 。然后如果最右侧不是 1 ,而是 0 ,假设最右边的 1 位于第 m 位,那么减去 1 之后,第 m 位就变成了 0 ,然后 m 位之后的 0 全部变成了 1 。比如 1100 ,减去 1 之后,就变成了 1011

再看 n & (n - 1)

n - 1 的作用,是把最右边的 1 变成了 0 (其再右侧的 0 变成了 1),左边的所有位都保持不变。接下来,我们把 n - 1n 按位取与运算(n & (n - 1)),那么在左边全部不变的前提下,右边的那些刚才从 0 变成 1 的位又回到了 0 的状态。比如 1100 ,减去 1 变成了 1011 ,然后 1100 & 10111000。所以,把一个整数减去 1 再与自己按位取与,会把该整数的最右边的 1 变成 0

应用场景 1 ——计算一个数的二进制表示中有几个 1

题目:输入一个整数,输出该整数二进制表示中 1 的个数

这个题目不难,最不济就依次和 1 做按位与,然后右移,再按位与... 每次按位与之后看一下结果是不是 1 。这个解法的循环次数与输入的二进制表示长度有关系,结合我们上面的 n & (n - 1) ,我们可以有如下解法:

    int countOf1(int n) {
        int count = 0;
        while (n != 0) {
            count++;
            n = n & (n - 1);
        }
        return count;
    }

上面的解法中,每次都把 n 的最右边的 1 变成了 0 ,直到 n 自己变成 0 ,那么变了几次,就说明 n 的二进制表示里就有几个 1

应用场景 2 —— 判断一个正整数是不是 2 的整数倍

题目:输入一个正整数,判断该正整数是否是 2 的整数倍

这个题目也不难,可以不停地通过除以 2 看余数是否为 0 来判断,但是这样需要计算的次数也和输入的大小有关系。从二进制的角度考虑,一个数是不是 2 的整数倍其实就是它的二进制表示是不是只有一位为 1 ,如果是,那它就是 2 的整数倍,否则就不是。基于这个认知,加上 n & (n - 1) 把一个数的二进制表示的最右边的 1 变成 0 ,我们可以构思如下算法:

    boolean isPowerOf2(int n) {
        return (n & (n - 1)) == 0;
    }

如果一个数把最右边的 1 变成 0 之后,就彻底变成了 0 ,那么这个数的二进制表示就只有一个 1 ,即它肯定是 2 的整数倍。

参考

https://stackoverflow.com/questions/4678333/n-n-1-what-does-this-expression-do

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

1 participant