位操作
位操作
Bit Operation
一、按位操作是在单个字节的层面上对一个或多个位模式或二进制数字符号进行
的操作。处理器支持这种快速简单的操作,而且可以用来比较和计算数值。
l按位操作比除法快得多,是乘法的几倍速度,有时候也比加法快得多。
![](https://img2020.cnblogs.com/blog/1509441/202005/1509441-20200516124710231-1146066268.png)
二、基本技巧
1.XOR
myBits ^ 0 : 不变
myBits ^ 1 : 翻转
2.左移位相当于乘以2的指数
x << n = x * (1 << n)
8 << 2 = 8 * (1 << 2) = 32
3.按位右移相当于一个除以2的指数
00011001 >> 2 = 00000110
00011001 >> 4 = 00000001
三、位操作
1、Set Bit
def setBit(a, n): return a | (1<<n)
2、Clear Bit
def clearBit(a, n): return a & (~(1<<n))
3.Toggle Bit
def toggleBit(a, n): return a ^ (1<<n)
4.Test Bit
def testBit(a, n): result = a & (1<<n) return result != 0
5.将整数转换为Bits(二进制) 此处只考虑了正数
def toBinary(n): sb = [] if n < 256: upper = 128 else: upper = 32768 i = upper while i > 0: if n & i != 0: sb.append(str(1)) else: sb.append(str(0)) i = i >> 1 return ''.join(sb)
6.将Bits(二进制)转换为整数 此处只考虑了正数
def convertBits2Int(binary): length = len(binary) result = 0 if length > 16: raise ValueError("Only Supports 16 Bits") for i in range(length): c = int(binary[i]) if (c != 0 and c != 1): raise ValueError("binary can only be 0 or 1") #result += c << (length - i - 1) result = (result << 1) + c return result
7.用Bits展示小数。
给定一个数(十进制小数,如3.72),用字符串将这个数传入,打印它的二进制表示。如果这
个数不能表示为二进制,打印‘ERROR’。
def convertDecimal(f): str_f = str(f).split(".") int_part, dec_part = divmod(f, 1) int_part = int(int_part) print(int_part, dec_part) int_s = "" while (int_part > 0): r = int_part % 2 int_part >>= 1 int_s = str(r) + int_s dec_s = [] while (dec_part > 0): if (len(dec_s) > 32): print("".join(dec_s)) raise ValueError("Not Support") if (dec_part == 1): dec_s.append(str(dec_part)) break r = dec_part * 2 if (r >= 1): dec_s.append("1") dec_part = r - 1 else: dec_s.append("0") dec_part = r return int_s + "." + "".join(dec_s)
8.将HEX转换为整数
def hex2int(s): digits = "0123456789ABCDEF" val = 0 for i in range(len(s)): c = s[i].upper() d = digits.index(c) val = 16 * val + d return val
9.将整数转换为HEX
def int2hex(d): digits = "0123456789ABCDEF" if d == 0: return "0" hex = "" while (d > 0): digit = d % 16 hex = digits[digit] + hex d = d // 16 return hex
方法一: O(N)
def bitCountA(n): count = 0 while (n != 0): if (n & 1 != 0): count += 1 n = n>>1 return count
方法二:O(k) (n & (n – 1) == 0)可以检测的是末位是否为1
def bitCountB(n): count = 0 while (n != 0): n = n & (n - 1) count += 1 return count
11.下一个2的幂数
给定一个整数n, 找到下一个数(这个数比n大,且是2的幂数)
def next2Power(n): while (n & (n-1) != 0): n = n & (n-1) return n << 1
12.检测两个整数的是否有相反符号
给定两个整数,检查他们是否有相反的符号
def isOppositeSigns(a, b): return (a^b) < 0
13.判断符号
def isPositiveInteger(n): return (n >> 31) == 0
14.不使用分支计算一个整数的绝对值
def absoluteA(a): mask = a >> 31 result = (a + mask) ^ mask return result
法二:
def absoluteB(a): mask = a >> 31 result = (a ^ mask) - mask return result
15.就地(in-place)整数交换
def swap2(a, b): a = b - a b = b - a a = a + b print(a, b)
法二:
def swap3(a, b): a = a ^ b b = a ^ b a = a ^ b print(a, b)
16.将整数A转换为整数B
计算将整数A转换为整数B所需要的位数
def convertA2B(a, b): count = 0 c = a ^ b while (c != 0): c = c & (c - 1) count += 1 return count
17.Amazing Mask
给定两个32-bit的数,N和M,以及两个比特位置 i 和 j 。写一个方法,这个方法可
以将N的i到j之间的值设置为M(即,M变成N的i到j之间的一个子串)
def amazingMask(n, m, i, j): allOne = ~0 left = allOne - ((1<<(j+1))-1) right = (1<<i)-1 mask = left | right return (n & mask) | (m << i)
18.不使用算术运算符进行添加
写一个两数相加的函数。不可以使用+或者任何算术运算符。
def add(a, b): if b == 0: return a sum = a ^ b carry = (a & b) << 1 return add(sum, carry)
19.找到丢失的数字(一个或多个)
方法:异或 略
20.找到数组[1-n]中重复的一个数,和一个缺失的数
def printTwoElements(arr): for i in range(len(arr)): if arr[abs(arr[i]) - 1] > 0: arr[abs(arr[i]) - 1] = -arr[abs(arr[i]) - 1] else: print("The repeating element is", abs(arr[i])) for i in range(len(arr)): if arr[i] > 0: print("and the missing element is", i + 1)
21.找到下一个最小/最大整数(二进制表示,与原数值有相同多个1) **
def getBit(n, index): return ((n & (1<<index))>0) def setBit(n, index, b): if b: return n | (1<<index) else: return n & (~(1<<index)) def getNext(n): if n <= 0: return -1 index = 0 countOnes = 0 # Find first one. while (not getBit(n, index)): index += 1 # turn on next zero while( getBit(n, index) ): index += 1 countOnes += 1 n = setBit(n, index, True) # turn off previous one index -= 1 n = setBit(n, index, False) countOnes -= 1 # set zeros i = index - 1 while (i >= countOnes): n = setBit(n, i, False) i -= 1 # set ones i = countOnes - 1 while (i >= 0): n = setBit(n, i, True) i -= 1 return n
def getPrevious(n): if (n <= 0): return -1 index = 0 countZeros = 0 # find first zero while( getBit(n, index) ): index += 1 # turn off next 1 while( not (getBit(n, index)) ): index += 1 countZeros += 1 n = setBit(n, index, False) # turn on previous zero index -= 1 n = setBit(n, index, True) countZeros -= 1 # set ones i = index - 1 while (i >= countZeros): n = setBit(n, i, True) i -= 1 # set zeros i = countZeros - 1 while (i >= 0): n = setBit(n, i, False) i -= 1 return n
22.Reservoir Sampling
在一个无穷的数据流中,挑选一个概率相等的数字。
import random def reservoirSampling(items, k): sample = items[0:k] for i in range(k, len(items)): j = random.randrange(1, i + 1) if j <= k: sample[j - 1] = items[i] return sample
写一个算法,计算n阶乘结果中尾部0的个数
def findTrailingZeros(n): count = 0 i = 5 while (n / i >= 1): count += n//i i *= 5 return count
24.最大公约数
def gcd(a, b): if b > a: return gcd(b, a) if a % b == 0: return b return gcd(b, a % b)