您的位置:首页 > 其它

使用移位运算和加减法实现乘除法

2016-04-07 19:41 260 查看
这个想法是在做leetcode 的题目29 Divide
Two Integers时产生的,原题描述如下:

Divide two integers without using multiplication, division and mod operator.

If it is overflow, return MAX_INT.

就是说不用乘除取余运算来实现两个int醒变量的整除,然后如果溢出的话就返回INT_MAX。

先把问题简化一下,不考虑溢出问题,并且假设被除数n大于除数m大于0,嗯,基于这个假设,剩下的就是纯粹的算法部分了。说到整除问题,有n/m==k+r(r==n mod m),也就是我们小学学过的被除数除以除数等于商加余数。根据这个公式很自然的想到用n逐次减去m直到差小于m,代码如下;
int i=0;
while (n>=m)
{
n-=m;
i++;
}
return i;


如果n和m比较接近的话,这样做还是很快的,但是对于一般情况,其时间复杂度为O(n/m),有些捉急,尤其是n特别大而m又很小的时候,简直不能忍,按这种思路提交的算法会提示超时(意料之中)。那么有没有别的方法呢?显然有!答案就是位运算。

使用左移和右移可以很方便地实现乘除2^的n次方,而 n/m==k+r 即 m*k==n-r 即 m*(2^l1+2^l2+……+2^ls)==n-r ,即m<<l1+m<,l2+……+m<<ls==n-r,于是整除运算就转化为移位运算和加减运算。然后可以写出如下代码:
int k=0,i=o;
while (n>=m)
{
if (n>=m<<i)
{
k+=1<<i;
n-=m<<i;
++i;
}
else
{
i--;
}
}
return k;

这样一来,一般情况下的时间复杂度大大降低,只有O(k的二进制表示的位数)。
同理,整数乘法也可以用位运算来实现。
int i=0,k=0;
while (m)
{
if (m>=1<<i)
{
k+=n<<i;
m-=1<<i;
i++;
}
else
{
i=0;
}
}

以上就是我能想到的方法,然后具体到这个题目的话,还要考虑除数为0以及溢出问题,比如被除数为-2^31时该怎么解决。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: