-
判断奇偶数
可以这样:就是将这个数和1进行与运算,如果结果是1就是奇数,0就是偶数
因为1的二进制最低位是1,其他位都是0,与运算就可以将其他位都变成0,最低位是0还是1决定于这个数的最低位是0还是1 -
获取二进制位是0还是1
可以将1左移到该位,然后和这个数进行与运算,将运算的结果再右移回来,看结果是多少就是多少了 -
不用判断语句,求整数的绝对值
方法一:
/*
* 当数字的最高位是1时(即负数时)就是将这个数乘与-1,这样就变成正数
* 当数字时正数时乘与1,不变
*/
return num * (1 - ((num >>> 31) << 1));
方法二:
//当num为正时: num >> 31=0;num ^ (num >> 31))=num
//当num为负时: num >> 31=-1;num ^ (num >> 31))=num的反码,再加上1就是原码了
return (num ^ (num >> 31)) - (num>> 31);
- 交换两个整数变量的值,要求空间复杂度是0
int a=10;
int b=20;
a=a^b;
b=a^b;
a=a^b;
end(补充小知识):
- 对于int型的,1 <<35和1<<3的结果是相同的.对于左边的操作数是long型的,最大是64位,所以对右边的操作数模64
- 对于异或的性质:
①可以理解成不进位的加法:1+1=0;0+0=0;1+0=1
②交换律:可以任意交换运算因子的位置,结果不变
③结合律:(a^b) ^c=a ^ (b ^c)
④对于任何数x,都有x^x=0,x ^0=x, 同自己求异或为0,同0求异或为自己
⑤自反性: A^ B ^ B=A^0=A, 连续和同一个因子做异或运算,最终结果为自己
下面做一个小题:
@Test
public void test1()
{
/*
* 1-1000这些1000个数放在含有1001个元素的数组里面,
* 只有唯一的一个元素重复,其他均只出现一次.设计一个算法,
* 每一个元素只能访问一次,不能使用辅助空间,将这个重复的数找出来
*/
//先构造这样子的数组
int N=11;
int[] a=new int[N];
for (int i = 0; i < a.length-1; i++)
{
a[i]=i+1;
}
//随机产生0到10的随机数和0-10的随机下标
int temp=(int)(Math.random()*10+1);
int index=(int)(Math.random()*10+1);
a[N-1]=a[index];
a[index]=temp;
System.out.println(Arrays.toString(a));
/*
* 数组上面已经构造完毕,下面进行算法处理
* 思路是这样的:
* 一个数和自己与是0,0和任何数异或是任何数,
* 所以我们就将整个数组所有的数异或,然后再和1到1000的
* 1000个数异或,这样子1-1000的数就会重复,异或的作用就是消除掉了
* 然后多出了一个重复的数,这个数就是要求的数
*/
temp=0;
//从1到10的异或运算
for (int i = 1; i < N; i++)
{
temp=temp^i;
}
for (int i = 0; i < a.length; i++)
{
temp=temp^a[i];
}
System.out.println(temp);
/*
* 另外的暴力方法
* 思路如下:
* 就是新建一个数组用来储存某一个数在上面的的数组出现的次数
* 若出现,就在新建的数组的相应位置进行加一处理,然后在扫描
* 新的数组,若数组的值是2,这个位置的下标就是要找的值
*/
int[] b =new int[N];
for (int i = 0; i < a.length; i++)
{
b[a[i]]++;
}
for (int i = 0; i < b.length; i++)
{
if(b[i]==2)
{
System.out.println(i);
break;
}
}
}
题2:一个数组,只有一个数是出现一次,其他都是出现了两次,叫你找出只出现一次的那个数(一直异或就行)
题3: 实现一个函数,输入一个整数,输出该数二进制表示中1的个数,比如4的二进制100,有一个是1,所以输出1
@Test
public void test2()
{
/*
* 实现一个函数,输入一个整数,输出该数二进制表示中1的个数
* 比如4的二进制100,有一个是1,所以输出1(这里写三种思路)
*/
/*
* 思路一:
* 就是int型的数字最多三十二位的,所以我们将1从第零位开始向左移x位,
* 然后和这个进行与运算,然后和1向左移x位的数字进行比较,若相等这个位置的数字就是1
*/
Scanner in=new Scanner(System.in);
int a=in.nextInt();
in.close();
System.out.println(Integer.toBinaryString(a));
int count=0;
for (int i = 0; i < 32; i++)
{
if((a&(1<<i))==(1<<i))
{
count++;
}
}
System.out.println("①:"+count);
/*
* 思路二:
* 就是将这个数字进行无符号右移,然后再和1进行与运算
* 若是结果是1就证明该位是1,否则就是0
*/
count=0;
for (int i = 0; i < 32; i++)
{
if(((a>>>i)&1)==1)
{
count++;
}
}
System.out.println("②:"+count);
/*
* 思路三:
* 先明白x&(x-1)的效果就是将x这个数字中的所有1中最低位的1消掉
* 这里说明一下,就是将一个数减一,要么是在最低位的1进行减一,
* 要么就是向高位进行借1,然后就会将所有的1中最低位的1的位置开始
* x-1和x的0和1是刚刚好相反的,这里比如:9 -->1001
* x --->1001
* x-1--->1000
* 所以两个数做与运算的话就会将最后面那个1变成0了
*/
count=0;
while(a!=0)
{
a=a&(a-1);
count++;
}
System.out.println("③:"+count);
}
题4:
用一条语句判断一个整数是不是2的整数次方
这个有前面的基础还是挺简单的,因为是不是2的整数次方
可以转化为是不是二进制中是不是只有一个1
这个就可以使用x&(x-)==0就可以判断了
题5:
将整数的奇偶位进行交换
@Test
public void test4()
{
/*
* 将整数的奇偶位进行交换
* 思路:
* 先将这个数和01 01 01 01 ....进行与运算得到的是奇数上的数字a,
* 偶数上的数字已经全部变成0了
* 然后将这个数和10 10 10 10 ....进行与运算,得到的是偶数上的数字b,
* 奇数上的数字已经全部变成0
* 然后将a左移一位得到c,b右移一位得到d
* 然后c和d进行异或运算得到交换的数
*/
int a=9;
int ji=a&0x55555555;
int ou=a&0xaaaaaaaa;
a=(ji<<1)^(ou>>1);
System.out.println(a);
}
题6:
0-1间浮点数的二进制表示
@Test
public void test5()
{
/*
* 0-1间浮点数的二进制表示
* 给定一个介于0和1之间的实数,打印它的二进制表示
* 如果该数字无法精确使用32位以内的二进制表示,
* 则打印error
*/
double a=0.3;
StringBuffer number=new StringBuffer("0.");
a=a*2;
while(a>0)
{
if(a>=1)
{
a=a-1;
number.append("1");
a=a*2;
}
else
{
number.append("0");
a=a*2;
}
if(number.length()>34)
{
System.out.println("error");
break;
}
}
System.out.println(number.toString());
}
题7:
数组中只有一个数出现了一次,其他数都出现了k次,请输出出现了一次的数
@Test
public void test6()
{
/*
* 数组中只有一个数出现了一次,其他数都出现了k次
* 请输出出现了一次的数
* 思路:
* 首先得知道这样一个知识点,比如:
* 两个相同的二进制数进行不进位加法时,结果就是0,
* 十个相同的十进制数进行不进位加法时,结果就是0,
* m个相同的m进制数进行不进位加法时,结果就是0,
* 可以自己写几个数验证一下,因为m进制,m个数,
* 这个数乘与m,最低位肯定是0,不进位,所以高位又是0
* 知道这些,然后就利用这个进行处理,就是将这些数变成k进制的
* 然后将他们进行不进位加法运算,出现了k次的数就会被消除掉
* 剩下的就是出现一次的数,然后将k进制转化成十进制
*/
int[] a= {2,2,2,9,9,9,7,7,7,3,3,3,6,6,6,0,0,0,123};
char[][] b=new char[a.length][];
int k=3; //因为这里的数字都是出现3次
int maxlength=0; //将最大的长度保存下来,因为后面求的数转化成十进制需要知道有多少位
for (int i = 0; i < b.length; i++)
{
//将里面的数字全部转化成k进制,并且翻转过来
b[i]=new StringBuffer(Integer.toString(a[i], k)).reverse().toString().toCharArray();
if(b[i].length>maxlength)
{
maxlength=b[i].length;
}
}
//然后进行不进位加法,就是将相应位的数字加起来,然后再相应地取k模
int[] temp=new int[maxlength];
for (int i = 0; i < b.length; i++)
{
for (int j = 0; j < maxlength; j++)
{
if(j>=b[i].length)
{
temp[j]=temp[j]+0;
}
else
{
temp[j]=temp[j]+(b[i][j]-'0');
}
}
}
//相应地取k模,然后转成十进制
int number=0;
for (int i = 0; i < maxlength; i++)
{
number=number+(temp[i]%k)*(int)(Math.pow(k, i));
}
System.out.println(number);
}