前言
最近在刷牛客的剑指offer和leetcode,刷的过程中会遇到各种各样的算法,用此系列贴记录下来。
位运算属实是奇妙方法,这次碰到的两题用位运算都可以把空间复杂度降到O(1)。
一共是两种方法,分别是&(与)另一种是^(异或)。
先来说&
题目描述
输入一个整数 n ,输出该数32位二进制表示中1的个数。其中负数用补码表示。
用暴力就是把n转化成二进制,然后数里面1的个数就好了
负数就相对麻烦一点,涉及到int的临界值问题
&运算:
当一个数n与(n-1)做&运算的时候,会消除掉最右边的一个1
0110&0101=0100
妙
这样一来,用了几次&运算就说明它有几个1了
代码
class Solution {
public:
int NumberOf1(int n) {
int num=0;
while(n){
num++;
n=n&(n-1);
}
return num;
}
};
11行代码解决了,短小精悍。
^异或:
leetcode136:只出现一次的数字
题目描述
给定一个非空整数数组,除了某个元素只出现一次以外,其余每个元素均出现两次。找出那个只出现了一次的元素。
示例 1:
输入: [2,2,1]
输出: 1
示例 2:
输入: [4,1,2,1,2]
输出: 4
重复出现的题我下意识就会用哈希表,表里没有的加进去,有的删了,最后剩下的就是出现一次的。
代码:
class Solution {
public:
int singleNumber(vector<int>& nums) {
set<int> ans;
for(auto i:nums){
if(ans.count(i)==0){
ans.insert(i);
}
else
ans.erase(i);
}
int an;
for(auto i:ans){
an=i;
}
return an;
}
};
然后看官方解答,发现官方用的异或,属实太妙了
0^a=a
a^a=0
满足交换律和结合律(这一点很重要,如果这一条不成立,这题就不能这么算)
那么用0去依次异或整个数组,剩下来的就是那个只出现一次的数
整个运算里所有的成双的数字都会变成0(交换律和结合律),最后只会剩下单独的数字
代码:
class Solution {
public:
int singleNumber(vector<int>& nums) {
int temp=0;
for(auto i:nums){
temp^=i;
}
return temp;
}
};
位运算用的少,也不是很熟。在某些情况下有很妙的作用,平时还是要多积累,肚子里有货才能有骚操作。