LeetCode(29)Divide Two Integers
来源:互联网 发布:淘宝新店怎么提升销量 编辑:程序博客网 时间:2024/06/05 17:50
题目内容
Divide two integers without using multiplication, division and mod operator. 求出两个数相除的商,禁用乘法或者除法或者取模运算。
题目分析
最容易的想到的办法,是把除法转化为减法,就像把乘法转化为加法一样,提交后发现,这个做法超时了,比如遇到2147483647/3这种时候,被除数很大,除数很小,基本都会超时。所以应该要使用一个特别的方法来提高效率。我想应该是位运算了。但是不知该如何写。参考了一下官网答案。发现实在很巧妙。如下,我把它微微改了一下,更好理解一些:
//官网答案,我的微改版class Solution {public: int divide(int dividend, int divisor) { long long a=abs(dividend); //(long long) dividend中的(long long)是为了防止-2147483648带来的溢出,下行同理。 long long b=abs(divisor); int res=0; while(a>=b){ long long c=b; for(int i=0;c<=a;i++){ a-=c; res+=1<<i; c=c<<1; } } return ((dividend^divisor)>>31) ? (int)(-res) : (int)(res);//判断是否为负数 }};
//官网实际答案class Solution {public: int divide(int dividend, int divisor) { long long a = abs((double)dividend); long long b = abs((double)divisor); long long ret = 0; while (a >= b) { long long c = b; for (int i = 0; a >= c; ++i, c <<= 1) { //std::cout<<"1-1 a="<<a<<", c="<<c<<" ,i="<<i<<" ,ret="<<ret<<std::endl; a -= c; ret += 1 << i; //std::cout<<"1-2 a="<<a<<", c="<<c<<" ,i="<<i<<" ,ret="<<ret<<std::endl; } } return ((dividend^divisor)>>31) ? (int)(-ret) : (int)(ret); }};
这个算法要理解起来,只需明白它提速的基本原理。
现在用两个例子谈谈它的基本原理。基本原理是,dividend非常大,所以把它切割成几块,一块一块地和divisor计算商,再把这些商都加起来就可以了。在切割的时候,各个小块是不均匀的。第1块的大小正好是divisor的大小,第2块的大小正好是divisor扩大2倍的大小,第3块的大小正好是divisor扩大2²倍的大小,第4块的大小正好是divisor扩大2³倍的大小......以此类推,直到把dividend分割完毕。以计算 49/7 = ? 为例子来看看这个过程。把上面代码中的注释恢复。可以看到下面的结果
1-1 a=49, c=7 ,i=0 ,ret=0
1-2 a=42, c=7 ,i=0 ,ret=1
1-1 a=42, c=14 ,i=1 ,ret=1
1-2 a=28, c=14 ,i=1 ,ret=3
1-1 a=28, c=28 ,i=2 ,ret=3
1-2 a=0, c=28 ,i=2 ,ret=7
49 / 7 = 7
c就是每次切割的小块,a就是每次拿走一小块之后a还剩下的数。
上面这个例子展示了正好整除的情况,那么其实还有不整除的情况,这样切出的小块中,最后一块是没法进入for循环中的,这时while循环就起作用了,来让最后单出来的一块也参与运算,直到a<b时停止,此时a被分割结束了,a/b=0不再对商的累加做贡献了。用64/7 = ?这个例子来看看。结果如下
1-1 a=64, c=7 ,i=0 ,ret=0
1-2 a=57, c=7 ,i=0 ,ret=1
1-1 a=57, c=14 ,i=1 ,ret=1
1-2 a=43, c=14 ,i=1 ,ret=3
1-1 a=43, c=28 ,i=2 ,ret=3
1-2 a=15, c=28 ,i=2 ,ret=7
1-1 a=15, c=7 ,i=0 ,ret=7
1-2 a=8, c=7 ,i=0 ,ret=8
1-1 a=8, c=7 ,i=0 ,ret=8
1-2 a=1, c=7 ,i=0 ,ret=9
64 / 7 = 9
另外,一开始我的代码是这样的,超时的代码
//我的超时版代码 int divide1(int dividend, int divisor) { if (divisor==0||dividend==0) return 0; if(divisor==1) return dividend; else if(divisor==-1) return -dividend; int negative_flag=0; if((dividend<0)&&(divisor>0)){ dividend=-dividend; negative_flag=1; } else if((dividend>0)&&(divisor<0)) { divisor=-divisor; negative_flag=1; }else if((dividend<0)&&(divisor<0)){ divisor=-divisor; dividend=-dividend; } int count=0; while(dividend>=divisor){ count++; dividend-=divisor; } count=(negative_flag==1)?(-count):(count); return count; }
小结:
(1) for循环的条件体写法学习了,初始条件用i表示,结束条件用a表示。原来还可以初始条件和结束条件用不同的变量来表示。
update : 2015-01-04
虽然大概知道上面那个写法的原理,但是真正自己写出来时,还是要经过一翻调试和egd case的检验。
//100msclass Solution {public: int divide(int dividend, int divisor) { //eg. 100 / 3 = 33; if (dividend == 0 || divisor == 0) return 0; if (dividend == INT_MIN && divisor == -1) return INT_MAX; if (divisor == 1) return dividend; long long l_dividend = abs((long long)dividend); long long l_divisor = abs((long long)divisor); // 用long long, 否则int a = abs(INT_MIN) = INT_MIN; long long a = l_dividend; long long b = l_divisor; long long res = 0; long long each = 1; while (a >= b) { //如果a < b,可以return0. //std::cout<<"a = "<<a<<", b = "<<b<<", res = "<<res<<", each = "<<each<<std::endl; while (a >= b) { //std::cout<<"b="<<b<<", res = "<<res<<"each = "<<each<<std::endl; each = each<<1; b = b <<1; } res += (each>>1); a -= (b>>1); each = 1; b = l_divisor; } return ((dividend ^ divisor)>>31) ? -res:res; //异或 }};
- leetcode 29: Divide Two Integers
- LeetCode(29)Divide Two Integers
- [leetcode 29] Divide Two Integers
- [leetcode] 29 Divide Two Integers
- leetcode 29 Divide Two Integers
- Leetcode 29 Divide Two Integers
- LeetCode 29 - Divide Two Integers
- leetcode 29 -- Divide Two Integers
- leetcode 29:Divide Two Integers
- leetcode 29: Divide Two Integers
- Leetcode#29 Divide Two Integers
- LeetCode(29)Divide Two Integers
- LeetCode-29 Divide Two Integers
- Leetcode#29||Divide Two Integers
- leetcode-29 Divide Two Integers
- leetcode 29:Divide Two Integers
- leetcode 29:Divide Two Integers
- LeetCode 29: Divide Two Integers
- 分享三个iframe自适应高度的例子
- jquery右下角弹出提示框的实现代码
- 面试题之自创 大数相乘
- Windows 7 Task Scheduler Start a Program
- Windows, Unix and ANSI C API Comparison
- LeetCode(29)Divide Two Integers
- 外部排序
- 用C语言模拟面向对象编程(上)
- [LeetCode] Binary Tree Zigzag Level Order Traversal
- 木桶论新解
- WindowXP下PHP5开发环境配置
- 面向对象的三个基本特征
- 全面理解面向对象的 JavaScript
- 基于CentOS6.0-64定制系统iso制作(修改)