一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第10天,点击查看活动详情。
位运算符
Java中给我们提供了很多位运算符,主要有以下内容
| 标题 | ||
|---|---|---|
| << | 左移 | 左移一位相当于该数乘以2 |
| >> | 右移 | 右移一位相当于该数除以2 |
| & | 与 | 有0则0 |
| | | 或 | 有1则1 |
| ~ | 非 | 1变0,0变1 |
| 异或 | 相同为0,不同为1 |
虽然位运算在平时用的比较少,但是在某些场景下使用起来还是很方便
使用场景
1.判断一个数是奇数还是偶数
一般情况下这种场景我们都是使用i%2==0来判断i的奇偶性,但是这里我们也可以使用与(&)运算符
来判断,因为一个数的二进制表示中,从低位到高位,只有第一位会决定这个数的奇偶性(如果第一位为1,则即该数为奇数,否则为0,该数为偶数),所以我们可以用该数和1进行与运算,就可以判断出结果
x & 1 == 1则为奇数
x & 1 == 0则为偶数
2.求一个数二进制中位为1的个数
编写一个函数,输入是一个无符号整数(以二进制串的形式),返回其二进制表达式中数字位数为 '1' 的个数
根据按位与的性质,只有当前位置运算的都是1,结果才是1,所以我们只需要将32个位置分别为1的时候和n进行运算,如果结果为0,说明当前二进制位置是0,否则为1,代码如下:
fun hammingWeight(n: Int): Int {
var count = 0
for (index in 0 until 32) {
if (((1 shl index) and n) != 0) {
count++
}
}
return count
}
还有个比较有意思的做法,可以直接消除二进制末尾的1,那就是n&(n-1),这个代码可以将二进制中最后一个1变成0,那么我们可以用此性质,判断将一个数二进制位全部变成0所需要的次数,也就是题目的答案,即
fun hammingWeight(n: Int): Int {
var count = 0
var num = n
while (num!=0){
count++
num = num and (num-1)
}
return count
}
3. 只出现一次的数字
给定一个非空整数数组,除了某个元素只出现一次以外,其余每个元素均出现两次。找出那个只出现了一次的元素。
拿到这道题最先想到的就是遍历数组,然后使用HashMap存储遍历过的数据,key为数字,value为出现的次数,最后遍历HashMap获取value==1的key就是结果
fun singleNumber(nums: IntArray): Int {
val temp = HashMap<Int, Int>()
for (num in nums) {
val value = temp[num]
if (value == null) {
temp[num] = 1
} else {
temp[num] = value + 1
}
}
var result = -1
temp.forEach { (k, v) ->
if (v == 1) {
result = k
}
}
return result
}
这样虽然可以求解,但是需要O(N)的额外空间,如果使用位运算,则可以做到O(1)的空间复杂度,对于这道题,我们可以使用异或运算,因为异或运算满足以下性质
- x^0=x 即0异或任何数都是原来的数
- x^x=0 即任何数异或本身结果都是0
- a^b^c=(a^b)^c=a^(b^c)=b^(a^c) 即异或满足交换律和结合律
由题目可知,除了一个数字出现一次,其余都出现2次,那么我们可以将出现2次的数字先分别进行异或然后再与只出现一次的数字异或,异或性质2告诉我们, x^x=0,那么出现2次的数字异或结果都是0,公式就变成了0^0^...0^0^x(x为只出现一次的数字),异或性质1告诉我们x^0=x,所以公式的运算结果就只有x了,即题目答案,代码如下
fun singleNumber(nums: IntArray): Int {
var result=0
for (num in nums) {
result = result xor num
}
return result
}