您的位置:首页 > 其它

【leetcode】Divide Two Integers

2014-05-20 19:52 211 查看
题目:不用乘、除、取模运算来实现除法。

减法可以实现除法在是我们早就知道的,但是可能会出现问题,比如极端情况,a = 0x7FFFFFFF,b = 1,求a/b,这要减法运算多少次?

回想下我们开始学习计算机的时候,涉及到的进制之间的转换,就是给定你一个十进制数,写出他的二进制,刚开始的时候很傻,就按着书上的方法去不停的除以2,除以2,除以2,。。。可笑的是居然天真的算过1024的二进制,更可笑的是,这样的方法算出来后,当时还很高兴。。。

对进制转化熟悉了以后,我们就不再这么算了,比如给我们一个十进制数47,我们会首先想到 32,接下来 47 - 32 = 15,想到 8,接下来 15 - 8 = 7, 想到 4 ,到2, 到 1。然后将各自对应的幂次位上写1.

我们这时为什么不再每次除2, 除2 的运算了呢? 因为这样太慢了,我们总是可以找到最接近 它的2的幂次的数,然后剩余的部分进行相同的操作,最后得到结果。

本题的减法实现除法也是相同思路,当除数很小时,就决定了每次操作的步长很小,就需要循环更多的次数。所以通过上面的进制转化的启发,我们决定应该给步长乘以一个放大因子。而且这个放大因子是2的幂次。

被除数 - i * 除数,随着i 每次加1 就是我们通常想到的减方法。

被除数 - 2 ^ i * 除数,

而一个数乘以2的幂次 恰好可以用移位来代替,这就不需要乘法了。

unsigned int remainder = dividend;
int consult = 0;
while (remainder >= divisor)
{
int power = 0;
while (remainder  >= (divisor  << power))
{
remainder -= (divisor << power);
consult += (1 << power);
power++;
}
}
核心的思想就是这些了,跟我们分析十进制转换的问题不同的是,这里总是从最小开始,试探着使用更大的步长。但本质上是一致的。

问题本身还有些比较繁琐的地方,涉及到有符号整形,最大最小值就够闹心,当然,我们可以在程序的实现中,将给定的参数强制转换成更高长度的类型,比如long long 来处理。

int Abs(int n){

int sign = n >> 31;
int re = n ^ sign;
return (re - sign);
}

int divide(int dividend, int divisor) {

if(divisor == 1)
return dividend;
if(0x7fffffff == dividend && 0x7fffffff == divisor)
return 1;
if (0x80000000 == dividend && 0x80000000 == divisor)
return 1;

//get the sign
int sign = divisor ^ dividend;
// get absolute value.
dividend = Abs(dividend);
divisor = Abs(divisor);

unsigned int remainder = dividend; int consult = 0; while (remainder >= divisor) { int power = 0; while (remainder >= (divisor << power)) { remainder -= (divisor << power); consult += (1 << power); power++; } }
if(sign < 0)
consult = -consult;
return consult;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: