JAVA位运算符有:左移( << )、右移( >> ) 、无符号右移( >>> ) 、位与( & ) 、位或( | )、位非( ~ )、位异或( ^ ),除了位非( ~ )是一元操作符外,其它的都是二元操作符。
关于补码:
计算机中存整数n是用补码存的:如果n为正数,则原码 = 补码 = 反码;如果n为负数,则补码 = 反码 + 1
正数右移,高位用0补,负数右移,高位用1补,当负数使用无符号右移时,用0进行补位(自然而然的,就由负数变成了正数了)
左移一位相当于乘以2,右移一位相当于除以2
负数的右移:需要保持数为负数,所以操作是对负数的二进制位左边补1。如果一直右移,最终会变成-1,即(-1)>>1是-1。 2.
负数的左移:和整数左移一样,在负数的二进制位右边补0,一个数在左移的过程中会有正有负的情况,所以切记负数左移不会特殊处理符号位。如果一直左移,最终会变成0。
我的记忆方法就是:
位与&100,位或|101,位异或^同0异1
写一个函数,求两个整数之和,要求在函数体内不得使用+、-、*、/四则运算符号。
public int Add(int num1,int num2) {
while (num1 != 0){
int temp = num1 ^ num2;
num1 = (num1 & num2) << 1;//进位
num2 = temp;//无进位和
}
return num2;
}
输入一个整数 n ,输出该数32位二进制表示中1的个数。其中负数用补码表示。
思路:
如果整数不等于0,那么该整数的二进制表示中至少有1位是1。先假设这个数的最右边一位是1,那么该数减去1后,最右边一位变成了0,其他位不变。再假设最后一位不是1而是0,而最右边的1在第m位,那么该数减去1,第m位变成0,m右边的位变成1,m之前的位不变。
上面两种情况总结,一个整数减去1,都是把最右边的1变成0,如果它后面还有0,那么0变成1。那么我们把一个整数减去1,与该整数做位与运算,相当于把最右边的1变成了0,比如1100与1011做位与运算,得到1000。那么一个整数中有多少个1就可以做多少次这样的运算。
public int NumberOf1(int n) {
int count=0;
while(n!=0){
count +=1;
n = (n-1)&n;
}
return count;
}
实现函数 double Power(double base, int exponent),求base的exponent次方。**代码:**考虑base=0/exponent=0/exponent<0的情况 。
注意:
1.保证base和exponent不同时为0。
2.不得使用库函数,同时不需要考虑大数问题
3.有特殊判题,不用考虑小数点后面0的位数。
算法思路:
public double Power(double base, int exponent) {
if(exponent==0)
return 1;
if(base==0)
return 0;
int flag=1;
double res=1;
if(exponent<0){
flag =-1;
exponent = -exponent;
}
while(exponent!=0){
res = res*base;
exponent -= 1;
}
if(flag==-1){
res = 1/res;
}
return res;
}
一个整型数组里除了两个数字只出现一次,其他的数字都出现了两次。请写程序找出这两个只出现一次的数字。输出时按非降序排列。
思路1:利用哈希表
public int[] FindNumsAppearOnce (int[] array) {
// write code here
// 用于返回结果
int[] res = new int[2];
// 创建一个哈希表
HashMap<Integer,Object> set = new HashMap<>();
for(int i = 0; i < array.length; i++){
// 如果已经被当作key了,那就直接remove掉
if(set.containsKey(array[i])){
set.remove(array[i],null);
}else{
// 否则就添加进去
set.put(array[i],null);
}
}
int i = 0;
// 最后拿出来放进返回结果的数组中进行返回
for(Integer num:set.keySet()){
res[i++] = num;
}
return res;
}
思路2:位运算
利用异或运算的同0异1
详细思路:
public int[] FindNumsAppearOnce (int[] array) {
// 先将全部数进行异或运算,找出这两个不同的数相异或的结果
int tmp = 0;
for(int num: array){
tmp ^= num;
}
// 找到那个可以充当分组去进行与运算的数(也就是找到两个数不同的那一位)
// 从最低位开始找起
int mask = 1;
while((tmp & mask) == 0){
mask <<= 1;
}
// 进行分组,分成两组,转换为两组 求出现一次的数字 去求
int a = 0;
int b = 0;
for(int num:array){
if((num & mask) == 0){
a ^= num;
}else{
b ^= num;
}
}
// 因为题目要求小的数放前面,所以这一做个判断
if(a > b){
int c = a;
a = b;
b = c;
}
return new int[]{a,b};
}
求1+2+3+…+n,要求不能使用乘除法、for、while、if、else、switch、case等关键字及条件判断语句(A?B:C)
思路一:使用递归
//若用递归:
if (n == 1) return n;
return n + Sum_Solution(n-1);
//换成位运算即可
public int Sum_Solution(int n) {
boolean flag=(n==1)||((n+=Sum_Solution(n-1))>0);
return n;
}
思路二:使用数学公式(右移相当于除以2)
public int Sum_Solution(int n) {
int sum = 0;//初始化结果
sum = (int)(n + Math.pow(n,2)) >> 1;//通过右移一位来代替除以2,注意要强转一下
return sum;
}
—《双人行》 司南
谁在吟唱
扶琴曲调
油纸伞上细雨如银毫
一拢白衣笑的心荡漾
仍是余音袅袅
小女自是难忘
在水一方