LeetCode371/29 两整数之和/两数相除

本文介绍如何利用位运算实现两整数之和及两数相除的算法,详细解析了位运算中的加法原理及高效除法的实现方式。
原题目
两整数之和:

不使用运算符 + 和 - ​​​​​​​,计算两整数 ​​​​​​​a 、b ​​​​​​​之和。
示例 1:
输入: a = 1, b = 2
输出: 3
示例 2:
输入: a = -2, b = 3
输出: 1

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/sum-of-two-integers

两数相除

给定两个整数,被除数 dividend 和除数 divisor。将两数相除,要求不使用乘法、除法和 mod 运算符。
返回被除数 dividend 除以除数 divisor 得到的商。
示例 1:
输入: dividend = 10, divisor = 3
输出: 3
示例 2:
输入: dividend = 7, divisor = -3
输出: -2
说明:
被除数和除数均为 32 位有符号整数。
除数不为 0。
假设我们的环境只能存储 32 位有符号整数,其数值范围是 [−231, 231 − 1]。本题中,如果除法结果溢出,则返回 231 − 1。

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/divide-two-integers

题目分析

题目一:
不使用运算符+和-,说明不能直接对两数字加减,可以用位运算
两个整数a, b; a ^ b是无进位的相加; a&b得到每一位的进位;让无进位相加的结果与进位不断的异或, 直到进位为0;
位运算中的加法

我们先来观察下位运算中的两数加法,其实来来回回就只有下面这四种:

0 + 0 = 0
0 + 1 = 1
1 + 0 = 1
1 + 1 = 0(进位 1)
仔细一看,这可不就是相同位为 0,不同位为 1 的异或运算结果嘛~

异或和与运算操作

我们知道,在位运算操作中,异或的一个重要特性是无进位加法。我们来看一个例子:

a = 5 = 0101
b = 4 = 0100

a ^ b 如下:

0 1 0 1
0 1 0 0
———
0 0 0 1
a ^ b 得到了一个无进位加法结果,如果要得到 a + b 的最终值,我们还要找到进位的数,把这二者相加。在位运算中,我们可以使用与操作获得进位:

a = 5 = 0101
b = 4 = 0100

a & b 如下:

0 1 0 1
0 1 0 0
————
0 1 0 0
由计算结果可见,0100 并不是我们想要的进位,1 + 1 所获得的进位应该要放置在它的更高位,即左侧位上,因此我们还要把 0100 左移一位,才是我们所要的进位结果。

那么问题就容易了,总结一下:

a + b 的问题拆分为 (a 和 b 的无进位结果) + (a 和 b 的进位结果)
无进位加法使用异或运算计算得出
进位结果使用与运算和移位运算计算得出
循环此过程,直到进位为 0
参考链接:https://leetcode-cn.com/problems/two-sum/solution/wei-yun-suan-xiang-jie-yi-ji-zai-python-zhong-xu-y/

注:LeetCode不支持负数左移。

完整代码

题目一:

int getSum(int a, int b){
    int sum=a,carry=b;
    while(carry)
    {
    int c=sum;
    sum=sum^carry;
    carry=(unsigned)(c&carry)<<1;
    }
    return sum;
}

题目二:

int divide(int dividend, int divisor)
{
    int res=0,flag=1;
    if(dividend==INT_MIN&&divisor==-1||dividend==INT_MAX&&divisor==1)
        return INT_MAX;
    if(dividend==INT_MIN&&divisor==1||dividend==INT_MAX&&divisor==-1)
        return INT_MIN;
    if(dividend<0&&divisor>0||dividend>0&&divisor<0)
        flag=-1;
    long dividend1=fabs(dividend);
    long divisor1=fabs(divisor),divisor2=divisor1;
    while(dividend1>=divisor2)
    {
        int i=0;
        while(dividend1>=divisor1)
        {
            dividend1-=divisor1;
            divisor1=divisor1<<1;
            res+=1<<i;
            i++;
        }
        divisor1=divisor2;
    }
    res*=flag;
    return res;
}

class Solution {
public:
    int divide(int dividend, int divisor) {
        if(dividend == INT_MIN && divisor == -1){//负数最小值除-1只能得到正数最大数
            return INT_MAX;
        }
        int symbol = 1;//默认符号为正
        if(dividend<0&&divisor>0||dividend>0&&divisor<0){//判断结果正负
            symbol = -1;
        }
        long dividend1 = abs(dividend);
        long divisor1 = abs(divisor);
        long res = 0;
        while(dividend1 >= divisor1){
            long temp = divisor1;
            int k = 1;
            while(dividend1 >= temp<<1){//循环n次,找k=2^n个除数,使被除数无法在被除
                temp = temp<<1;
                k = k << 1;
            }
            res += k;//加入结果
            dividend1 -= temp;//求剩余被除数
        }
        return symbol*res;
    }
};
总结

了解位运算的使用

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

Baal Austin

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

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

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

打赏作者

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

抵扣说明:

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

余额充值