您的位置:首页 > 编程语言 > Java开发

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

2017-03-11 16:08 489 查看
与位运算相关的编程算法技巧的总结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 ;
}


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



------------------------------------------------------------------------------------------------------------------------------------------------

总结完毕!
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: