目录
一.& 与运算符
当转换为二进制之后,对应位置同时为1的时候才为1
如:
如何判断一个数是否为2的幂次,可以采用这种方法(n&(n-1))==0
2的n次方-1和一个数&操作相当于此数与2的n次方的取模操作 比如(16-1)&4==4%16==4
1.判断一个数的二进制最大的相邻1的个数
public int MaxNearOne(int num) {
int cnt = 0;
while (num != 0) {
//num = num & (num << 1);
num = num & (num >> 1);
cnt++;
}
return cnt;
}
2.判断两个数的二进制斜向相邻
public boolean isAdjacent(int num1, int num2) {
int x = num1 | num2;
return (x & (x << 1)) !=0;
}
二.| 或运算符
当转换为二进制之后,对应位置有一个为1的时候就为1
2的幂次相加可以这样计算:cnt | = num;
三.^ 异或运算符
当转换为二进制之后,对应位置相同为0,不同为1(或者记住奇数个1为0,偶数个1为1)
异或的一些小性质:
- 任何数和0做异或运算,结果仍然是原来的数,即 a⊕0=a
- 任何数和其自身做异或运算,结果是 0,即 a⊕a=0
- 异或运算满足交换律和结合律,即 a⊕b⊕a = b⊕a⊕a = b⊕(a⊕a)=b⊕0=b
四.~ 非运算符
反转每一位的二进制,将1变成0,0变成1
五.<< 左移运算符
将当前数字的二进制形式向右移n位,右边补0,相当于乘以2
注意:一个数x左移n位,相当于 x*2^n
六.>>右移运算符
将当前数字的二进制形式向右移n位,左边补(正数补0,负数补1),相当于除以2
七.>>> 无符号右移:
即右移之后,无论该数为正还是为负,右移之后左补0。
八.lowbit
求二进制数字最后一个1的位置
return cnt&(-cnt);
求二进制数组最后一个0的位置
cnt=~cnt;
return cnt&(-cnt);
九.综合运用
1.将二进制数的第x位置变成1
/**
*
* @param num 需要置1的数字
* @param position 需要置1的位置
* @return 置1后的数字
*/
public static int changetoOne(int num,int position){
num|=(1<<(position-1));
return num;
}
测试数据:
changetoOne(8, 2); //10
2.将二进制数的第x位置变成0
/**
*
* @param num 需要置0的数字
* @param position 需要置0的位置
* @return 置0后的数字
*/
public static int changetoZero(int num,int position){
num&=~(1<<(position-1));
return num;
}
测试数据:
changetoZero(15, 2); //13
3.求二进制中1的个数
当求二进制中1的个数
可以使用res&=(res-1),这样可以去掉二进制中的最后一个1;
/**
*
* @param num 所要求的数
* @return 二进制总共含有多少个1
*/
public static int countOne(int num){
int count=0;
while (num!=0){
num&=num-1;
count++;
}
return count;
}
countOne(217); //5
,以此类推,总共5个1
4.计算1之间的最大间距
力扣:力扣
给定一个正整数 n
,找到并返回 n
的二进制表示中两个 相邻 1 之间的 最长距离 。如果不存在两个相邻的 1,返回 0
。
如果只有 0
将两个 1
分隔开(可能不存在 0
),则认为这两个 1 彼此 相邻 。两个 1
之间的距离是它们的二进制表示中位置的绝对差。例如,"1001"
中的两个 1
的距离为 3 。
/**
* @param n 所要求解的数字
* @return 二进制之间1的最大间距
*/
public static int binaryGap(int n) {
int start = 0, end = 0, max = 0;//start为开始1的位置,end为结束1的位置,max记录end-start的最大值
while ((n & 1) != 1) {//判断n的最后一位是否为1
start++;
n = n >> 1;//每一次后移一位
}
if (n == 1)//当n等于1的时候,说明n中仅含有1个1
return 0;
end = start;//将start变为end
while (n != 0) {
end++;
if ((n & 1) == 1) {//判断n的最后一位是否为1
max = Math.max(max, end - start);
start = end;
}
n = n >> 1;//每一次后移一位
}
return max;
}
5.只出现一次的数字
力扣:力扣
给你一个 非空 整数数组 nums
,除了某个元素只出现一次以外,其余每个元素均出现两次。找出那个只出现了一次的元素。
你必须设计并实现线性时间复杂度的算法来解决此问题,且该算法只使用常量额外空间。
分析:阅读题目可以知道,只有一个元素出现一次,其他的数字出现且仅出现了两次,这个时候就可以使用异或运算来进行操作
- 任何数和0做异或运算,结果仍然是原来的数,即 a⊕0=a
- 任何数和其自身做异或运算,结果是 0,即 a⊕a=0
- 异或运算满足交换律和结合律,即 a⊕b⊕a = b⊕a⊕a = b⊕(a⊕a)=b⊕0=b
由此就可以写出代码了
public int singleNumber(int[] nums) {
int single = 0;
for (int i = 0; i < nums.length; ++i) {
single ^= nums[i];
}
return single;
}
6.颠倒二进制位
力扣:力扣
颠倒给定的 32 位无符号整数的二进制位。
public int reverseBits(int n) {
int rev = 0;
for (int i = 0; i < 32 && n != 0; ++i) {
//每次将数n第x位上的送到第33-x位上
rev |= (n & 1) << (31 - i);
//每次的无符号右移只是为了n & 1可以求出第x位上的数字是1还是0
n >>>= 1;
}
return rev;
}
7.只出现一次的数字 II
力扣:力扣
给你一个整数数组 nums
,除某个元素仅出现 一次 外,其余每个元素都恰出现 三次 。请你找出并返回那个只出现了一次的元素。
你必须设计并实现线性时间复杂度的算法且不使用额外空间来解决此问题。
public int singleNumber(int[] nums) {
int res=0;
for(int i=0;i<32;++i){
int total=0;
for (int num : nums) {
total+=(num>>i)&1;
}
if (total % 3 != 0)
res |= 1 << i;
}
return res;
}
8.只出现一次的数字 III
力扣:力扣
给你一个整数数组 nums
,其中恰好有两个元素只出现一次,其余所有元素均出现两次。 找出只出现一次的那两个元素。你可以按 任意顺序 返回答案。
你必须设计并实现线性时间复杂度的算法且仅使用常量额外空间来解决此问题。
public int[] singleNumber(int[] nums) {
int xor = 0;
for (int num : nums) {
xor ^= num;
}
int lowbit = xor & (-xor);
int ans1 = 0, ans2 = 0;
for (int num : nums) {
if ((num & lowbit)!=0) {
ans1 ^= num;
} else {
ans2 ^= num;
}
}
return new int[]{ans1, ans2};
}
9.消失的数字
力扣:力扣
数组nums
包含从0
到n
的所有整数,但其中缺了一个。请编写代码找出那个缺失的整数。你有办法在O(n)时间内完成吗?
public int missingNumber(int[] nums) {
int n=nums.length;
int x1=0,x2=0;
for(int i=0;i<n;++i){
x1^=i;
x2^=nums[i];
}
x1^=n;
return x1^x2;
}
10.奇偶位数
力扣:力扣
给你一个 正 整数 n
。
用 even
表示在 n
的二进制形式(下标从 0 开始)中值为 1
的偶数下标的个数。
用 odd
表示在 n
的二进制形式(下标从 0 开始)中值为 1
的奇数下标的个数。
返回整数数组 answer
,其中 answer = [even, odd]
public int[] evenOddBit(int n) {
int[] ans = new int[2];
//n每次向右移动一位,i在0和1之间跳动变换
for (int i = 0; n > 0; i ^= 1, n >>= 1) {
ans[i] += n & 1;
}
return ans;
}
11.找到两个数组的前缀公共数组
给你两个下标从 0 开始长度为 n
的整数排列 A
和 B
。
A
和 B
的 前缀公共数组 定义为数组 C
,其中 C[i]
是数组 A
和 B
到下标为 i
之前公共元素的数目。
请你返回 A
和 B
的 前缀公共数组 。
如果一个长度为 n
的数组包含 1
到 n
的元素恰好一次,我们称这个数组是一个长度为 n
的 排列 。
public int[] findThePrefixCommonArray(int[] A, int[] B) {
int[] ans = new int[A.length];
long p = 0, q = 0;
for (int i = 0; i < A.length; ++i) {
p |= 1L << A[i];
q |= 1L << B[i];
//bitCount方法的作用是找到p&q运算后1的个数
ans[i] = Long.bitCount(p & q);
}
return ans;
}