这个想法是在做leetcode 的题目29Divide 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时该怎么解决。