【算法】关于 i & (1<<j) 和 1 & (i>>j) 的解释
一、 i & (1<<j)
1<<j表示二进制表示的1(即0001)的所有位向左平移j个单位后的数,如j=1,则平移后的结果是0010,此时得到数2。若j=3,平移后的结果是1000,此时得到数8。向左平移j位,即表示将原来的数乘上2^j。可以类比十进制,所有位左移j位,相当于在后面添了j个0,即乘上10^j,在二进制中,即乘上2^j。
&在此处表示按位与,即两个二进制表示的数,在对应位置上进行取并的操作,都为1时取1,否则取0。如1010(十进制的10)和0101(十进制的5)进行按位与操作后,得到的是0000(十进制的0)。
i & (1<<j)则表示 i 和 1<<j(即2^j) 按位与后得到的数。1<<j的二进制表示只有第j个位置(从右往左数,从0开始)上的数是1,其余位置上的数是0,i和1<<j 进行按位与操作时,i的第j个位置是1就返回1<<j(判断语句中即为true),i的第j个位置是0就返回0(判断语句中即为false)。
ex:i=18,j=3
00010010
00001000
________
00000000
具体地,
当i=0时,任何j都不满足。
当i=1时,j=0 满足条件。
当i=2时,j=1 满足条件。
当i=3时,j=0,1 满足条件。
当i=4时,j=2 满足条件。
当i=5时,j=0,2 满足条件。
当i=6时,j=1,2 满足条件。
当i=7时,j=0,1,2 满足条件。
当i=8时,j=3 满足条件。
...
当i=2^n-1时,j=0,1,2,...,n-1 满足条件。
归纳一下,如果j表示数组a(长度为n)的索引,循环结构如下,则表示依次选取数组a的一个子数组进行操作,直到选到它本身。
for (let i=1; i<1<<n; ++i) {
for (let j=0; j<n; ++j) {
if (i & (1<<j)) {}
}
}
例子:LeetCode 2044. 统计按位或能得到最大值的子集数目(中等),代码参考文献1
var countMaxOrSubsets = function(nums) {
let cnt=0,res=0,n=nums.length;
for (let i=1; i<1<<n; ++i) {
let tem=0;
for (let j=0; j<n; ++j) {
if (i & (1<<j)) {
tem |= nums[j];
}
}
if (tem>res) {res=tem;cnt=0;}
if (tem == res) {cnt++;}
}
return cnt;
};
例如,当a=[3,1]时,
i=1,j=0时,取[3],tem=3,res=3,cnt=1;
i=2,j=1时,取[1],tem=1,res=3,cnt=1;
i=3,j=0时,取[3],tem=3;
i=3,j=1时,取[1],tem=3,res=3,cnt=2。
返回2。
二、 1 & (i>>j)
1 & (i>>j)相当于i 右移 j 位后,若为奇数则返回1,若为偶数则返回0。代码相当于:
let a = i/(2**j);
if (a % 2 == 0) {
return 0;
} else {
return 1;
}
若i>=0 && i < 2^n ,j>=0 && j<n ,具体地,
当i=0时,任何j都不满足。
当i=1 时,j=0满足条件。
当i=2 时,j=1时满足条件。
当i=3 时,j=0,1时满足条件。
当i=4 时,j=2时满足条件。
当i=5 时,j=0,2时满足条件。
当i=6 时,j=1,2时满足条件。
当i=7 时,j=0,1,2时满足条件。
当i=8 时,j=3时满足条件。
...
当i=2^n-1 时,j=0,1,2,...,n-1时满足条件。
归纳,1 & (i>>j) 和i & (1<<j) 的效果一样,都是依次取出[0,1,2,...,n-1]的子集,直到取到其本身。

浙公网安备 33010602011771号