#初学算法,学了几个位运算符的使用方法,做个笔记
全局代码(附调试)
package 平台代码.CSDN.算法中的各种数;
import java.util.Arrays;
public class 位运算 {
/*1、判断一个数是不是2的幂*/
public static boolean isPowerOfTwo(int n){
return ((n & 0x80000000)==0) && (n&(n-1))==0;
//0x80000000是32位整数的最高位,与n相与结果为0,则 n>0
// 相邻两个二进制数相与结果为0,则为2的幂
}
/*2、判断一个数是不是 4的幂*/
//4的x次幂一定是2的x次幂,但反过来不同;
// 用数学归纳法,2的偶数次幂mod3余数为1 , 【此时一定是4的幂】
// 2的奇数次幂mod3余2
public static boolean isPowerofFour(int n){
return (n & 0x80000000)==0 && (n&(n-1))==0 && n%3==1;
} // 首先大于0 然后是2的幂 取3余数为1
/*3、判断整型转换为二进制后1的个数 */
// 二进制数1000 减1变为 0111 两个数组按位与操作,结果变为 0000
//所以记录消去1的次数即可
public static int hammingWeight(int n){
int count=0;
while(n>0){
n &= (n-1);
++count;
}
return count;
}
/*4、不用临时变量,实现两个数的交换 */
public static int[] swapNumber(int[] arr,int aSize,int returnSize){
arr[0] = arr[0] ^ arr[1]; //假设arr[0]和arr[1]为a和b,然后0与任何数异或都为数本身
arr[1] = arr[0] ^ arr[1]; //等价于 b = a^b^b = a^0 = a
arr[0] = arr[0] ^ arr[1]; //等价于 a = a^a^b = 0^b = b
return arr;
}
/*5、找出数组中只出现了一次的数*/
//相同的数字异或为0,0与任何数异或都是数本身。
//故将0和数组中所有数字进行异或。
//全部异或的结果就是只出现一次的数
public static int singleNumber(int[] nums){
int num=0; //将num与数组中所有数异或
for(int i=0;i<nums.length;i++){
num ^= nums[i];
}
return num;
}
/* 6、汉明距离:两个整数之间的 汉明距离 指 两个数组对应二进制位不同的位置的数目*/
//所以就是找出两个二进制数异或之后“1”的个数
public static int hanmingDistance(int x, int y){
int count=0;
int temp= x^y;
while(temp>0){
temp &= (temp-1); //temp-1 与temp 相与 消去temp高位上的1个1
++count; //消去“1” 的次数就是二进制中1的个数
}
return count;
}
/*7、判断二进制数是否是“10”交替出现 */
//将相邻的两位和 3 相与运算,
//相与的结果为3则为“11”,结果为0则为“00,全部排除这两种则为目标数
public static boolean hasAlternatingBits(int n){
while(n>0){
if((n & 3)==3 || (n & 3)==0){ // 两数相与要(),java中 == 大于 位运算符
return false; //一旦出现“11”和“00”,则非目标结果
}
n >>= 1;
}
return true;
}
/*8、子集的异或总和再求和 */
//将数组中的每个下标用二进制的一个比特位来表示,
//比如集合{a,b,c}中,用“010”表示其子集{b},“001”表示{c}
//所以是对 位数==数组长度的二进制数进行判断
public static int subSetXORSum(int[] nums){
int i,j,ans;
int sum=0;
for(i=0;i<(1<<nums.length);i++){
ans=0;
for(j=0;j<(nums.length);j++){ //这个位上的比特位和i相与==1,说明在集合中
if((i & (1<<j))==1){
ans ^= nums[j];
}
}
sum+=ans;
}
return sum;
}
/*9、不用加减号实现两数之和 */
//异或 的本质就是不进位加法
//与运算+左移1位 实质上就是进位加法
//所以 两数之和 = a^b + (a&b)<<1
public static int getSum(int a, int b){
if(b==0){
return a;
}
return b==0? a:getSum(a^b,(a&b)<<1);
}
/*10、二进制位插入 */
//题目:n、m表示二进制数,i、j表示比特位,将m插入n 的i~j位(i<j),不够0补齐
//第一步 i~j位赋0
//第二步 左移i位插入m
public static int insertBits(int n,int m, int i,int j){
int k=0;
for(k=i;k<j;++k){ //1、置0
n &= ~(long)1<<k; //n的第k位 取0(1取反为0),其余位为1
}
return n | m<<i; //2、左移i位插入(位或)m
}
public static void main(String[] args){
System.out.println(isPowerOfTwo(8)); //true
System.out.println(isPowerofFour(16));//true
int[] arr = {2,3};
System.out.println(Arrays.toString(swapNumber(arr, 2, 2))); // [3,2]
//数组直接syso输出的是数组地址,只能toString或循环遍历输出
int[] arr_1 = {1,2,3,4,5,4,3,2,1};
System.out.println(singleNumber(arr_1)); //5
//汉明距离
System.out.println(hanmingDistance(8,4)); //2
//“01”交替判断
System.out.println(hasAlternatingBits(10)); // true
//"子集的异或总和再求和"
int[] arr9 = new int[]{2,0,2,4};
System.out.println(subSetXORSum(arr9)); //16
//不用符号实习两数之和
System.out.println(getSum(6, 7)); //13
//10、插入
System.out.println(insertBits(12, 3, 1, 2)); //14
}
}
1、判断一个数是不是2的幂
/*1、判断一个数是不是2的幂*/
public static boolean isPowerOfTwo(int n){
return ((n & 0x80000000)==0) && (n&(n-1))==0;
//0x80000000是32位整数的最高位,与n相与结果为0,则 n>0
// 相邻两个二进制数相与结果为0,则为2的幂
}
2、判断一个数是不是 4的幂
- 4的x次幂一定是2的x次幂,但反过来不同;
- 用数学归纳法,2的偶数次幂mod3余数为1 , 【此时一定是4的幂】
- 2的奇数次幂mod3余2
public static boolean isPowerofFour(int n){
return (n & 0x80000000)==0 && (n&(n-1))==0 && n%3==1;
} // 首先大于0 然后是2的幂 取3余数为1
3、判断整型转换为二进制后1的个数
- 二进制数1000 减1变为 0111 两个数组按位与操作,结果变为 0000
- 所以记录消去1的次数即可
public static int hammingWeight(int n){
int count=0;
while(n>0){
n &= (n-1); //消去一个“1”
++count;//消“1”次数+1
}
return count;
}
4、不用临时变量,实现两个数的交换
public static int[] swapNumber(int[] arr,int aSize,int returnSize){
arr[0] = arr[0] ^ arr[1]; //假设arr[0]和arr[1]为a和b,然后0与任何数异或都为数本身
arr[1] = arr[0] ^ arr[1]; //等价于 b = a^b^b = a^0 = a
arr[0] = arr[0] ^ arr[1]; //等价于 a = a^a^b = 0^b = b
return arr;
}
5、找出数组中只出现了一次的数
- 相同的数字异或为0,0与任何数异或都是数本身。
- 故将0和数组中所有数字进行异或。
- 全部异或的结果就是只出现一次的数
public static int singleNumber(int[] nums){
int num=0; //将num与数组中所有数异或
for(int i=0;i<nums.length;i++){
num ^= nums[i];
}
return num;
}
6、汉明距离
- 两个整数之间的 汉明距离 指 两个数组对应二进制位不同的位置的数目所以就是找出两个二进制数异或之后“1”的个数
public static int hanmingDistance(int x, int y){
int count=0;
int temp= x^y;
while(temp>0){
temp &= (temp-1); //temp-1 与temp 相与 消去temp高位上的1个1
++count; //消去“1” 的次数就是二进制中1的个数
}
return count;
}
7、判断二进制数是否是“10”交替出现
-
将相邻的两位和 3 相与运算,
-
相与的结果为3则为“11”,结果为0则为“00,全部排除这两种则为目标数
public static boolean hasAlternatingBits(int n){
while(n>0){
if((n & 3)==3 || (n & 3)==0){ // 两数相与要(),java中 == 大于 位运算符
return false; //一旦出现“11”和“00”,则非目标结果
}
n >>= 1;
}
return true;
}
8、子集的异或总和再求和
- 将数组中的每个下标用二进制的一个比特位来表示,
- 比如集合{a,b,c}中,用“010”表示其子集{b},“001”表示{c}
- 所以是对 位数==数组长度的二进制数进行判断
public static int subSetXORSum(int[] nums){
int i,j,ans;
int sum=0;
for(i=0;i<(1<<nums.length);i++){
ans=0;
for(j=0;j<(nums.length);j++){ //这个位上的比特位和i相与==1,说明在集合中
if((i & (1<<j))==1){
ans ^= nums[j];
}
}
sum+=ans;
}
return sum;
}
9、不用加减号实现两数之和
- 异或 的本质就是不进位加法
- 与运算+左移1位 实质上就是进位加法
- 所以 两数之和 = a^b + (a&b)<<1
public static int getSum(int a, int b){
if(b==0){
return a;
}
return b==0? a:getSum(a^b,(a&b)<<1);
}
10、二进制特定位插入
- 题目:n、m表示二进制数,i、j表示比特位,将m插入n 的i~j位(i<j),不够0补齐
- 第一步 i~j位赋0
- 第二步 左移i位插入m
public static int insertBits(int n,int m, int i,int j){
int k=0;
for(k=i;k<j;++k){ //1、置0
n &= ~(long)1<<k; //n的第k位 取0(1取反为0),其余位为1
}
return n | m<<i; //2、左移i位插入(位或)m
}