首页 > 代码库 > 【leetcode】Divide Two Integers

【leetcode】Divide Two Integers

题目:不用乘、除、取模运算来实现除法。

减法可以实现除法在是我们早就知道的,但是可能会出现问题,比如极端情况,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;
}