与位运算相关的编程算法技巧的总结java实现

与位运算相关的编程算法技巧的总结java实现

计算机所有的运算最终都是转换为位运算和移位的操作,效率也很高,在很多场合具有很强的技巧,所以做个总结供大家学习。

1.1 交换a,b的值,不使用第三个变量?
通常使用第三个变量:
int a=3,b=4;
int temp;

temp=a;
a=b;
b=temp;

法一: 【法一需要考虑a+b会不会超过a表达的数值范围,导致内存溢出】
a=a+b;
b=a-b;         // 右边等价于a+b-b=====a
a=a-b;           //此时b等于a,右边等价于a+b-a====b


法二:
a=a^b;
b=a^b; // 右边等价于a^b^b=====a
a=a^b; //此时b===a; 此式右边等于a^b^a=====b

------------------------------------------------------------------------------------------------------------------------------------------------
1.2 实现一个函数,输入一个整数,输出为该整数的二进制表示有多少个1?
思路1: 判断该整数是否能被2整除,如果不能被2整除,则最后一位肯定为1,计数器加一,然后右移一位;
int Numberof1(int n){
int count=0;
while(n){
if(n&1) // if(n%2==1)
count++;

n=n>>1;
}
return count;
}

存在问题:如果把移位改为除以2,那样效率又太低,如果输入时一个负数,0x8000 0000右边移动一位,变为0xC000 0000 。而不等价于理想的右移动一位的时候相当于除以2,得0x4000 0000。这样最终就会都变为1,引起 死循环;
思路2: 思路1中右移n可能会导致是负数的时候造成死循环。那么我们改进,每次左移1.

int Numberof1(int n){
int count=0;
unsigned int flag=1;
while(flag){
if(n&flag) // 判断某位是否为1
count++;

flag=flag<<1;
}
return count;
}


思路3: (n-1)&n相当于把n的最右边一个1变为0;
n-1:相当于把最右边的1变为0,左边保持不变,该1右边的0变为1;10100---减1--->10011
(n-1)&n:10100---&---10011------------> 10 000
int Numberof1(int n){
int count=0;
while(n){
count++;
n=(n-1) && n;
}
return count;
}

------------------------------------------------------------------------------------------------------------------------------------------------
1.3 实现一个函数不用加减乘除求两个数的和
思路:num1^num2:相当于只做加法不做进位(不同为1,相同为0,此时都为1的二进制位没有进位);
num1&num2<<1:相当于进位(都为1,才为1.左移1位)
把上面两步相加,反复迭代即可。
public int add(int num1,int num2){
int sum,carray;
do{
sum=num1^num2;
carray=num1&num2<<1;
num1=sum;
num2=carray;
}while(num2!=0);
}

------------------------------------------------------------------------------------------------------------------------------------------------
1.4 判断一个数是不是2的整数次方?
思路:如果一个数是2的整数次方,那么这个数的二进制表示中有且仅有一位为1. (n-1)&n那么这个数唯一的一个1就会变为0;(n-1)&n==0 就是2的整数次方。
------------------------------------------------------------------------------------------------------------------------------------------------
1.5 两个整数m,n,改变多少位二进制表示才能从m变为n.
思路:求异或,然后求异或中有多少个1.
------------------------------------------------------------------------------------------------------------------------------------------------
1.6 一个整形数组里面除了两个数字,其他数字都出现了两次,找出只出现了一次的两个数字。时间复杂O(n),空间O(1)
思路:如果只有一个数字是只出现了一次,其他数字都出现了两次,那么只需要异或数组中的的所有元素,最后得到的值就是那个只出现一次的数字,出现偶数次的数字都被异或得0了。a^a==0。现在是两个只出现了一次的数字,那么想办法分组,每个组里面包含一个只出现一次的数字,要保证其他一样的数字出现在同一个组里。
首先 异或数组里面所有的数字得到一个结果值。由于有两个数字只出现了一次,其他数字异或抵消掉了,这两个不同的数字异或结果不等于0,结果的二进制表示中肯定至少有一位为1.我们找该结果的第一个为1的位置。这两个只出现一次的数字,肯定该对应位一个为1,一个为0.我们依据每个元素该位置是否为1 分为两组, 这2个不同的只出现一次的数字就被分到两个组里,数字出现两次的数字由于一样肯定会被分到同一个组里。 最后 ,分别异或两个组,得到两个数字就是唯一出现一次的两个不同的数字。
代码:(java)
public void findNumAppearOne(int[] a){
if(a==null || a.length<2)
return ;
int sum=0;
for(int i:a) sum^=i;
int index=findFirstBitIs1(sum); //发现第一个为1的位置;

int sum1=0;
int sum2=0;
for(int i:a){
if(isBit1(i,index)) //判断i的index位置是不是1;
sum1^=i;
else
sum2^=i;
}
System.out.println(sum1);
System.out.println(sum2);
}

public int findFirstBitIs1(int sum){//判断从右往左的第n位置是不是1,是1返回。
int index=0;
while((sum&1)==0){
sum=sum>>1;
index++;
}
return index;
}

public booleam isBit1(int i,int index){
i=i>>index;
return (i&1)==0 ;
}

好像总结完了,还没看到图片之类的养眼的,配个在线编程本题的图吧!^_^

与位运算相关的编程算法技巧的总结java实现_第1张图片
------------------------------------------------------------------------------------------------------------------------------------------------

总结完毕!






你可能感兴趣的:(算法,位运算)