算法
常用的一个等式:-n = ~(n - 1) = ~n + 1
获得int型最大值
1 2 3 4 5 6
| int getMaxInt(){ return (1 << 31) - 1; return ~(1 << 31); return (1 << -1) - 1; return ((unsigned int) - 1) >> 1; }
|
获得int型最小值
1 2 3 4
| int getMinInt(){ return 1 << 31; return 1 << -1; }
|
获得long类型的最大值
1 2 3 4
| long getMaxLong(){ return ((unsigned long) - 1) >> 1; return ((long)1 << 127) - 1; }
|
获得long最小值,和其他类型的最大值,最小值同理.
2运算
1 2 3 4
| n << 1 n >> 1 n << m n >> m
|
判断一个数的奇偶性
1 2 3
| boolean isOddNumber(int n){ return (n & 1) == 1; }
|
不用临时变量交换两个数(面试常考)
1 2 3
| void swap(int *a,int *b){ (*a) ^= (*b) ^= (*a) ^= (*b); }
|
通用版(一些语言中得分开写)
取绝对值
(某些机器上,效率比n>0 ? n:-n 高)
1 2 3 4 5 6
| int abs(int n){ return (n ^ (n >> 31)) - (n >> 31);
}
|
取两个数的最大值
(某些机器上,效率比a>b ? a:b高)
1 2 3 4
| int max(int a,int b){ return b & ((a-b) >> 31) | a & (~(a-b) >> 31); }
|
C语言版
1 2 3 4 5
| int max(int x,int y){ return x ^ ((x ^ y) & -(x < y));
}
|
取两个数的最小值
(某些机器上,效率比a>b ? b:a高)
1 2 3 4
| int min(int a,int b){ return a & ((a-b) >> 31) | b & (~(a-b) >> 31); }
|
C语言版
1 2 3 4 5
| int min(int x,int y){ return y ^ ((x ^ y) & -(x < y));
}
|
判断符号是否相同
1 2 3
| boolean isSameSign(int x, int y){ return (x ^ y) >= 0; }
|
计算2的n次方
1 2 3
| int getFactorialofTwo(int n){ return 2 << (n-1); }
|
判断一个数是不是2的幂
1 2 3 4 5
| boolean isFactorialofTwo(int n){ return n > 0 ? (n & (n - 1)) == 0 : false;
}
|
对2的n次方取余
1 2 3 4 5
| int quyu(int m,int n){ return m & (n - 1);
}
|
求两个整数的平均值
1 2 3 4 5 6 7 8
| int getAverage(int x, int y){ return (x + y) >> 1; } int getAverage(int x, int y){ return ((x ^ y) >> 1) + (x & y);
}
|
下面是三个最基本对二进制位的操作
从低位到高位,取n的第m位
1 2 3
| int getBit(int n, int m){ return (n >> (m-1)) & 1; }
|
从低位到高位.将n的第m位置设为1
1 2 3 4 5
| int setBitToOne(int n, int m){ return n | (1 << (m-1));
}
|
从低位到高位,将n的第m位置设为0
1 2 3 4 5
| int setBitToZero(int n, int m){ return n & ~(1 << (m-1));
}
|
另附一些对程序效率上没有实质提高的位运算技巧,一些也是位运算的常识(面试也许会遇到)
1 2 3 4 5 6
| n+1 = -~n n-1 = ~-n -n = ~n+1 -n = (n^-1)+1 x = a ^ b ^ x <=> if(x == a) x = b; if(x == b) x = a; sign(x) = !!n - (((unsigned)n >> 31) << 1)
|
获取整数二进制表示中最右侧的1
1
| n & (-n) <=> n & ~(n - 1)
|
二进制中1的个数
用到了n & (n - 1)
由x & (x - 1)消去x最后一位的1可知。不断使用 x & (x - 1) 消去x最后一位的1,计算总共消去了多少次即可。
1 2 3 4 5 6 7 8
| int countOnes(int num) { int count = 0; while(num != 0) { num = num & (num-1); count++; } return count; }
|
翻转
1 2 3 4 5 6 7 8 9
| unsigned int Bit_Reverse(unsigned int v) { v = ((v >> 1) & 0x55555555) | ((v << 1) & 0xaaaaaaaa); v = ((v >> 2) & 0x33333333) | ((v << 2) & 0xcccccccc); v = ((v >> 4) & 0x0f0f0f0f) | ((v << 4) & 0xf0f0f0f0); v = ((v >> 8) & 0x00ff00ff) | ((v << 8) & 0xff00ff00); v = ((v >> 16) & 0x0000ffff) | ((v << 16) & 0xffff0000); return v; }
|
输入两个数A和B,输出将A转换为B所需改变的二进制的位数。
首先,A异或B得到的是A和B中不相同位数组成的数,然后再求这个数二进制表示中1的个数,即为所求。
数组中只出现一次的数字
用到了n & (n - 1) 和 a ^ b ^ b = a
数组中,只有一个数出现一次,剩下都出现两次,找出出现一次的数
因为只有一个数恰好出现一个,剩下的都出现过两次,所以只要将所有的数异或起来,就可以得到唯一的那个数。
参考文章:http://zhedahht.blog.163.com/blog/static/2541117420071128950682/
数组中,只有一个数出现一次,剩下都出现三次,找出出现一次的数
因为数是出现三次的,也就是说,对于每一个二进制位,如果只出现一次的数在该二进制位为1,那么这个二进制位在全部数字中出现次数无法被3整除。
膜3运算只有三种状态:00,01,10,因此我们可以使用两个位来表示当前位%3,对于每一位,我们让Two,One表示当前位的状态,B表示输入数字的对应位,Two+和One+表示输出状态。
参考文章:http://zhedahht.blog.163.com/blog/static/25411174201283084246412/
数组中,只有两个数出现一次,剩下都出现两次,找出出现一次的数
有了第一题的基本的思路,我们可以将数组分成两个部分,每个部分里只有一个元素出现一次,其余元素都出现两次。那么使用这种方法就可以找出这两个元素了。
不妨假设出现一个的两个元素是x,y,那么最终所有的元素异或的结果就是res = x^y。并且res!=0,那么我们可以找出res二进制表示中的某一位是1。对于原来的数组,我们可以根据这个位置是不是1就可以将数组分成两个部分。x,y在不同的两个子数组中。而且对于其他成对出现的元素,要么在x所在的那个数组,要么在y所在的那个数组。
位操作实现加减乘除运算
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70
| int BinaryAdd(int a, int b) { int carry, add; do { add = a ^ b; carry = (a & b) << 1; a = add; b = carry; } while (carry != 0); return add; }
int BinarySub(int a, int b) { return BinaryAdd(a, BinaryAdd(~b, 1)); }
int BinaryMultiply(int a, int b) { bool neg = (b < 0); if(b < 0) b = -b; int sum = 0; map<int, int> bit_map; for(int i = 0; i < 32; i++) { bit_map.insert(pair<int, int>(1 << i, i)); } while(b > 0) {
int last_bit = bit_map[b & ~(b - 1)]; sum += (a << last_bit); b &= b - 1; } if(neg) sum = -sum; return sum; }
int BinaryDivide(int a, int b){ bool neg = (a > 0) ^ (b > 0); if(a < 0) a = -a; if(b < 0) b = -b; if(a < b) return 0; int msb = 0; for(msb = 0; msb < 32; msb++) { if((b << msb) >= a) break; } int q = 0; for(int i = msb; i >= 0; i--) { if((b << i) > a) continue; q |= (1 << i); a -= (b << i); } if(neg) return -q; return q; }
|
reference:
Prev: Python Tweepy 翻墙抓取Twitter信息
Next: 面向过程,面向对象,函数式