不用加减乘除做加法 从递归到迭代


该题目直接看最优的迭代解法很难看懂,因为没有一个递进理解的过程,所以需要先从简单的递归开始理解,然后再改进为更优的迭代解法。

题目描述

写一个函数,求两个整数之和,要求在函数体内不得使用 “+”、“-”、“*”、“/” 四则运算符号。

该问题是《剑指 Offer》中的第65题,在 LeetCode 中的难度为简单。
剑指 Offer 65. 不用加减乘除做加法

解题思路

解决该题目需要以下两个位运算知识:

  • 不考虑进位的话,两个 数字相加(+) 得到的结果和它们做 异或运算(^) 的结果是一样的。
  • 两个数字相加之后产生的 进位 ,与它们做 与运算(&) 得到的结果是一样的。

因此,要计算两个数(a 和 b)的加和,只需要将它们的 不考虑进位的加和结果(a ^ b) 和它们的 进位结果(a & b) 相加就可以了。
但是要注意一点,第 i i i 位的 加和结果 应该跟第 i − 1 i - 1 i1 位的 进位结果 相加(从右边第一位开始数),所以实际上应该是 a ^ b 与 (a & b) << 1 相加。
要得到 a ^ b 与 (a & b) << 1 的加和,仍然需要用它们的 不考虑进位的加和结果 和它们的 进位结果 相加。

显然,这是个递归的过程

递归解法

有了上面的思路,就可以写出如下的递归解法了。

public int add(int a, int b) {
    int aXORb = a ^ b;  // a 与 b 不考虑进位的加和
    int carry = (a & b) << 1;  // a 与 b 相加得到的进位结果
    if (carry == 0) return aXORb;  // 若进位为 0,说明 aXORb 就是最终结果,不用考虑进位了,直接将其返回
    else return add(aXORb, carry);  // 若进位不为 0,说明 aXORb 还需要与进位结果递归进行相加
}

迭代解法

最后将递归解法改为迭代的解法。
为了节约内存空间,直接使用a保存ab不考虑进位的加和(相当于递归解法中的aXORb变量)。
为了将进位结果带入下一次循环,使用b保存进位结果。
b != 0作为循环的终止条件,有以下两种情况:

  • b一开始即为 0,则不进入循环直接返回a即可。
  • 若进入循环,那么每次循环结束时b都会保存进位结果,当b等于 0 时,说明没有进位了,可以返回最终答案了。
public int add(int a, int b) {
    while (b != 0) {  // 若 b == 0,代表进位是 0 了,可以返回答案了;若 b 一开始就是 0,则 a 就是最终结果,直接返回
        int carry = (a & b) << 1;  // a 与 b 相加得到的进位结果
        a ^= b;  // 用 a 保存 a 与 b 不考虑进位的加和
        b = carry;  // 用 b 保存进位结果
    }
    return a;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

ZBH4444

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值