lintcode 给出两个整数a和b, 求他们的和, 但不能使用 + 等数学运算符。(增加实现逻辑减,语言使用python)

    lintcode中有这样一个题,是在不使用数学运算符的情况下,用位运算符实现两个数求和,关于这个问题,有不少朋友已经给出了自己的解法,这篇文章主要是记录了我在使用python2.7完成逻辑加之后,实现逻辑减的过程。

    首先贴上代码部分如下,中间docstring部分详细讲解了代码实现流程

# coding: utf-8   
""" 
使用位运算的方法计算两数的和,以及计算两数的差
@version: v1.0
@author: SoulReaperrX
@license: Apache Licence  
@contact: 407495044@qq.com 
@software: PyCharm 
@file: sumBitwise.py 
@time: 2018/6/13 19:17 
"""


def sumbitwise(a, b):
    """
    给出两个整数a和b, 求他们的和, 但不能使用 + 等数学运算符
    (原题连接:http://www.lintcode.com/zh-cn/problem/a-b-problem/)。

    实际上,数的相加规则如下,以13+17为例。
    1、首先各个位相加,十位1+1=2,个位3+7=0,进位为一
    2、然后得到进位数,10,将第一步得到的20和进位数10采用同样的方法继续加
    3、重复上述步骤,直到没有进位为止。

    那么我们考虑二进制的该方案如何实现,因为考虑到使用位运算。
    首先,2进制的转换在python中可以通过bin(num)函数实现,同样的,八进制可以用oct(num),16进制可以用hex(num)
    二进制转十进制,我们则可以使用将形如0b101的二进制数首先转换为str类型,然后取str[2:]即可,第二个下标默认是字符串长度
    我们得到二进制的13是1101,17是10001,那么我们考虑以上三步,只能运用到位运算符

    1、首先,1101+10001,不考虑进位时,为11100,进位为10
    2、我们将11100和进位相加,得到11110,如果没有进位,则输出
    3、否则重复上面两步
    那么位运算中,计算时1+1=0,1+0=1,0+1=1,0+0=0,这是一个典型的异或运算
    即同真同假时才为真。
    而得到进位的加法是纯粹的位运算与,1+1才为1,并进一位。
    因此我们可以这样coding。
    """
    str_bin_a = bin(a)  # 得到的是str类型的二进制
    str_bin_b = bin(b)  # 得到的是str类型的二进制
    bin_a = int(str_bin_a[2:], 2)
    bin_b = int(str_bin_b[2:], 2)
    if a == 0:
        return b
    if b == 0:
        return a
    summery = bin_a ^ bin_b  # 将二进制的a和b取异或运算summery
    carry = (bin_a & bin_b) << 1  # 将进位计算出来并且左移一位,和summery取异或
    return sumbitwise(summery, carry)


def subbitwise(a, b):
    """
     那么我们如何实现位运算符实现减法呢?我们来看两个位运算符的减法实现。
     我们以二进制9即1001和二进制5即0101为例。
     1001和0101的运算减结果为0100。
     这个计算中,被减数位为0,减数相同的位为1时,得到的结果数同位为1,这是因为被减数发生了退位。
     如果我们不考虑退位的情况,被减数的位为0时,且减数同位为1的情况下,我们默认将被减数该位看作2,
     再进行位的减法操作,我们可以得到
     1001       1201
     0101 ==>>  0101
     1100       1100
     修改成1201是纯粹为了方便理解,事实上,这也是一个典型的异或运算。
     这个操作中,由于我们在2^2这个位上,被减数借了一位,因此我们需要在之后把结果数中的位还回去
     也就是将结果数1100,还掉借的1000这一位
     1100
     1000
     0100
     来得到真实的结果数,而退位如何得到呢?我们之前分析过,只有被减数的位是0,减数同样的位是1,即
     xx0xxx
     xx1xxx
     这种情况时,才会需要退位
     也就是如下才会产生退位。
     0 0 1 1    被减数的位
     0 1 0 1    减数的位
     0 1 0 0    结果1表示有退位
     这是一个符合非A且B的运算,即~a&b为1时,产生了退位。
     同样是分析1001和0101,按照~a&b得到的退位是0100.
     而这个退位是从2^3这一位上借的,所以退位也需要左移一位,再与前面产生的结果取异或运算。
     于是,我们得到位运算符计算减法的算法。
     1、首先,将两个运算数进行异或运算得到summery
     2、然后,将两个运算数进行~a&b运算得到退位carry
     3、重复以上两步,直到没有退位

    """
    # 计算两数之差,并且不使用逻辑运算符+,而是使用位运算符
    str_bin_a = bin(a)  # 得到的是str类型的二进制
    str_bin_b = bin(b)  # 得到的是str类型的二进制
    bin_a = int(str_bin_a[2:], 2)
    bin_b = int(str_bin_b[2:], 2)
    if a == 0:
        return b
    if b == 0:
        return a
    summery = bin_a ^ bin_b  # 将二进制的a和b取异或运算得到summery
    carry = (~bin_a & bin_b) << 1  # 将进位计算出来并左移一位,准备和summery取异或
    return subbitwise(summery, carry)
if __name__ == '__main__':
    print sumbitwise(13, 17)
    print subbitwise(9, 5)

    对于python初学者,可能会产生疑惑的地方,这里大概解释一下。

    bin(number)函数是一个将十进制例如9数转换为形如'0b1001'的string类型数据的函数。

    bin_a = int(str_bin_a[2:], 2)是将str类型的str_bin_a转换为二进制形式的数据bin_a,因为python中二进制的定义是通过这样的方式:binary = int('str', 2)的方式。因此,我们通过截取之前得到的'0b1001'字符串的下标2至最后一位,得到二进制数。

    bin_a = int(str_bin_a[2:], 2)等价于bin_a = int('1001', 2)。

    一个补充的小知识点,string类型在使用str[index1:index2]截取字符串时,如果index2为空,则会截取index1开始到字符串结尾的一个子串。

    因为事实上大家面试做笔试题,或者有相关考试的时候,往往遇到的并不是在lintcode等等网站刷过的原题,所以适当的对lintcode上面的算法题进行举一反三是不错的提升方式,在这个过程中,大家也可以对某种算法或者思想的理解更加深入。我把这种方式当做一种学习方式,同时算是记录了自己的学习过程,希望和大家共同进步。

    后续能否实现使用位运算符进行乘法和除法运算呢?大家可以思考一下,欢迎讨论。


参考:

    1.csdn博客 -- wangyezi19930928的专栏。

    https://blog.csdn.net/wangyezi19930928/article/details/52516332


  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值