【Leetcode29】利用位运算对加减乘除的实现【Python】

Part1. 利用位运算实现乘法

思路:利用乘数的各位是否为1,将所有为1的位,让被乘数左移动相应的位数,然后相加

Ps:这里其实还有一种累加的思路,即通过将被乘数累加乘数次

# 5 * 3 = 15
# 5可以表示为 101 
# 3可以表示为 011
# Step1. 判断乘数为1的数位为第0位,和第1位
# Step2. 将被乘数左移动0位,得到101
# Step3. 将被乘数左移动1位,得到1010
# Step4. 所有数相加,即101+1010 = 5+10 = 15

# 程序实现
def Multiply(a, b):
    # Step1. 乘积的符号判定
    if (a < 0 and  b > 0) or (a > 0 and b < 0):
        flag = 1
    else:
        flag = 0
    # Step2. 取绝对值,将被乘数和乘数转换为正数
    a, b = abs(a), abs(b)
    ResultValue = 0
    while b:
        # 判断b的最后一位是否是1,如果是1,则a左移,b右移
        if b&1:
        	ResultValue = ResultValue + a
        	a = a<<1
        	b = b>>1 
    # 对于符号不同的,需要给结果添加一个符号
    if flag:
        ResultValue = -ResultValue
    return ResultValue
Part2. 利用位运算实现除法

思路:我想到的是减法,能被减多少次,那么商就为多少,但是效率太低,时间复杂度为O(n)

Tips:计算机中的数,向左移1相当于乘以2,向右位移1相当于除以2

那么,我们最先用dividend(被除数)除以一个大数,如2^n, 假设n初始值为31,然后不断减小n,当某个n满足 dividend / 2^n >=divisor)表示我们找到了一个足够大的数,这个数*divisor是小于等于dividend的,所以我们就可以减去2^n个divisor,以此类推。 时间复杂度为O(logN)

如果以100/3为例

2^n 是1,2,4,8…2^31 这种数,当n为31时,这个数特别大,100/2^n是一个很小的数,肯定是小于3的,所以循环下来,

当n=5时,100/32=3, 刚好是大于等于3的,这时我们将100-32*3=4,也就是减去了32个3,接下来我们再处理4,同样手法可以再减去一个3

所以一共是减去了33个3,所以商就是33

# 未考虑边界的限制,即当被除数和除数为2^31次时的情况。
def divide(a, b):
    if a == 0:
        return 0
    if a == -pow(2,31) and b == -1:
        return pow(2,31)-1
    # Step1. 商的符号判定
    if (a < 0 and  b > 0) or (a > 0 and b < 0):
        flag = 1
    else:
        flag = 0
    a, b = abs(a), abs(b)
    ResultValue = 0
    i = 31
    while i >=0:
        # 比较x是否大于y*(1<<i)=(y<<i),避免直接比较,因为不确定y*(1<<i)是否溢出
        # a>>i 即a/2^i
        if (a>>i) >= b:
            ResultValue = ResultValue + (1<<i)
            a = a - (b<<i)
		i = i-1
	if flag:
        ResultValue = -ResultValue
    return ResultValue
Part3. 利用位运算实现加法

思路:我没有想到,所以mark下别人的思路。利用异或和与的运算来表示加法。即不管是十进制加法还是二进制加法,其加的的过程在每一位看分为‘和’、‘进位’两个部分。‘和’要留在当前位,‘进位’加入到下一位。

  • 位的 异或 运算跟 求’和’ 的结果一致:

  • 位的 与 运算跟 求’进位‘ 的结果一致:

# 异或运算:A与B不同为1时,A、B的预算结果才为1,否则为0  (运算符:^)
# 主要在Python中,整数不是 32 位的,也就是说你一直循环左移并不会存在溢出的现象,
# 这就需要我们手动对 Python 中的整数进行处理,手动模拟 32 位 INT 整型。
# 具体做法是将整数对 0x100000000 取模,保证该数从 32 位开始到最高位都是 0。

def getSum(self, a, b):
    # 2^32
    MASK = 0x100000000
    # 整型最大值
    MAX_INT = 0x7FFFFFFF
    MIN_INT = MAX_INT + 1
    while b != 0:
        # 计算进位
        carry = (a & b) << 1
        # 取余范围限制在 [0, 2^32-1] 范围内
        a = (a ^ b) % MASK
        b = carry % MASK
    return a if a <= MAX_INT else ~((a % MIN_INT) ^ MAX_INT)
Part4. 利用位运算实现减法

思路:利用加法完成减法,即将减数取负,然后进行加法

Ps:关于如何取负,在计算机内部一般是先取反,然后+1

# 按位翻转(按位取反):将内存中表示数字的2进制数取反0取1,1取0 (运算符:~)
def negtive(a):
    return add(~a,1)

def subtraction(a, b):
    return add(a, negtive(b))
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 8
    评论
评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值