java中的位运算
- 前言
- 一、基础知识1
- 二、练习1
- 三、基础知识2
- 四、练习2
- 总结
前言
1)异或
2)原码、反码、补码
一、基础知识1
- 异或运算
按位相同为0,相反为1.
4 ^ 5 = 100 ^ 101 = 001- 运算特点
a)交换律,a ^ b ^ c = a ^ c ^ b
b)0 ^ n = n
c)n ^ n = 0
a)+b)+c):a ^ b ^ c ^ b = a ^ (b ^ b) ^ c = a ^ 0 ^ c = a ^ c
二、练习1
给定一个非空整数数组,除了某个元素只出现一次以外,其余每个元素均出现两次。找出那个只出现了一次的元素。
通过异或来完成相同元素的抵消。以Space – O(1)来完成。
a ^ a ^ b ^ b…y ^ y ^ z = 0 ^ 0 ^ … ^ z = z
public int singleNumber2(int[] nums) {
//res=0,0^n=n
int res = 0;
for(int num:nums){
res ^= num;
}
return res;
}
注:其它解法
1)HashSet添加set中未有元素、删除set中已在元素,最终得到只出现了单次的元素。(Time:O(n),Space:O(n))
2)将数组排序,判断相邻元素是否相等,来得到单一元素。(Time:O(nlog2n),Space:O(1))
3种解法都是在利用所给条件的特性+所学的基础知识下产生,所以我们不仅需要沉淀基础知识,还需锻炼分析转化问题的能力。(学习的两大核心)
三、基础知识2
- 原码、反码、补码
原码,即二进制定义所表示一个数。1->0001;2->0010;3->0011;…
反码,按位取反(符号位不算)。~1->1110;~2->1101;~3->1100
补码,反码+1。1111;1110;1101;注:Java中数据用补码存储。
正数,最高位用0表示,源码,反码、补码相等。
负数,最高位用1表示,源码、反码、补码不相等。
注:对于+0、-0,只用+0,-0用来表示另一个负数,所以同等bit表示,负数比正数多1,所以将负数转正数时需防止溢出。(以8bit为例)-128 到 127;即1 0000000 到 0 0000000。
想将Integer.Min_Value 转为正数时,需先将Integer.Min_Value用long来装入。
四、练习2
给定一个整数数组 nums,其中恰好有两个元素只出现一次,其余所有元素均出现两次。 找出只出现一次的那两个元素。你可以按 任意顺序 返回答案。
同样可以用HashSet、排序来解决,但是Time或Space复杂度较高。
采用异或。
1)同样将全部值异或在一起,有两个的就抵消,所以得到两个单值的异或值。
2)如何从一个异或结果值拆成两个值?通过取最低有效位(least significant bit)。取到最低位有1的地方(当然取任何一个1都可以,毕竟异或时,该位能为1,说明这两个值的该位一个为1一个为0).
3)将所有数分组,分为两组,固定位为1、固定位为0。(a b b c c d d e:{a b b c c }+{e d d },相同的会抵消,可简化为{ a }+{ e })
public int[] singleNumber(int[] nums) {
int xorsum = 0;
for (int num : nums) {
xorsum ^= num;
}
// 防止溢出(同等位数,负数比正数多1.如integer:2^31^ - 2^31 -1(因为+0占了一位正数))
//Integer.Min_Value最低有效位就是最高有效位。(只有符号位为1:-2^31^:0x8(1000)0000000)
//为什么这里(xorsum)&(-xorsum)能取到最低有效位(least significant bit,lsb)?参考上面的补码.
//4:0 000 0100(原码);0 000 0100(补码);-4:1 000 0100(原码);1 111 1011 + 1 = 1 111 1100(补码)
//0 000 0100 & 1 111 1100 = 0 000 1000(高位全为0,通过补码特性留住了最低有效位)
int lsb = xorsum == Integer.MIN_VALUE ? Integer.MIN_VALUE: xorsum & (-xorsum);
//通过上面找到的固定位数是否为1来分类。
int type1 = 0, type2 = 0;
for (int num : nums) {
if ((num & lsb) != 0) {
type1 ^= num;
} else {
type2 ^= num;
}
}
return new int[]{type1, type2};
}
总结
1)异或
2)原码、反码、补码
3)沉淀基础知识 + 锻炼分析转化问题