题目:

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

If it is overflow, return MAX_INT.

代码:

class Solution {
public:
int divide(int dividend, int divisor) {
if (divisor==) return dividend>= ? INT_MAX : INT_MIN;
if (divisor==- && dividend==INT_MIN) return INT_MAX;
// record negative or positive
int sign = ;
sign = dividend< ? -sign : sign;
sign = divisor< ? -sign : sign;
// transfer to non negative long long type & get rid of overflow
unsigned long long _dividend = abs((long long)dividend);
unsigned long long _divisor = abs((long long)divisor);
if ( _dividend < _divisor ) return ;
// using bit manipulation to simulate binary multiply
unsigned long step = ;
while ( _dividend > _divisor )
{
_divisor = _divisor << ;
step = step << ;
}
// cout << "step:" << step << endl;
// cout << "_divisor:" << _divisor << endl;
unsigned long res = ;
while ( _dividend >= abs((long long)divisor) )
{
while ( _dividend >= _divisor)
{
_dividend -= _divisor;
res = res + step;
}
_divisor = _divisor >> ;
step = step >> ;
}
return sign== ? res : -res;
}
};

tips:

这道题非常好,即考查了bit manipulation又考查了类型转换的细节。

做题的过程中,学习了下面这个blog的优秀思路(http://yucoding.blogspot.sg/2013/01/leetcode-question-28-divide-two-integers.html

1. 不让用乘法、除法、幂运算等。但还是要做除法,这个时候可以用bit manipulation。本质就是用二进制运算代替十进制运算。

  比如 155/3 ,如果不让你用除法,只允许用乘法或加法,该怎么做呢?

  做法1(加法):

      3+3+...+3+3==153,result=51

      这种解法最直观,但也最耗时,时间复杂度为O(n)

  做法2(乘法+加法):

      1)3*100=300>155 , 得知result<100,10个3*10大于被除数

      2)3*10=30<155, 得知result>10 1个3*10小于被除数

         155-30-30-30-30-30==5<30, result = result +50

      3) 3*1=3<5,得知result大于一个3*1小于10个3*1

        5-3=2<3,result = result +1 = 51

      最终得到的结果是 155 = 3*5*10^1 + 3*1*10^0 + 2。

      解释如下,如果用10的幂构成的多项式(多项式每个项目前面有固定的系数就是被除数);

      并在每一项前面配上一个变化系数(加颜色),155就被表示上述的形式

显然做法2的时间复杂度log(n)更低,按照题意的要求,乘以10这种做法肯定是不行了,所以把10换成2,改用移位运算,右移一次等于乘以2。

比如 15/3 = 3*2^2 + 3*2^0 , 可得商为2^2+2^0=5。

2. 这道题还有一个细节就是变量类型转换,以及涉及到边界的临界问题:

a) INT_MIN=-2147483648

但abs(INT_MIN) 呢?还是-2147483648。因为int的上限就是2147483647;因此如果除数被除数有一个是INT_MIN都没法变成正的啊!

如果是 unsigned long long v = abs(INT_MIN)呢?这种的可以么?结果是:18446744071562067968,还是不对。

好奇这个数咋来的呢?

复习了知识点:负数在计算机中以补码形式表示。

INT_MIN的补码形式是1000....000(31个0);

现在要把INT_MIN转成unsigned long long类型的,这中间发生了什么呢?

1) 把有符号转无符号数,如果是负数的话,要取补码

2) unsigned long long是64位的,INT_MIN是32位的;转换后高位要补上0

这就涉及到顺序的问题:先取补码还是先高位补0?

根据事实结果:先补高位的0,再取补码

补高位0:0...0(32个零)10...000(31个零)

取补码:a)先取反码 1...1(32个1)01...1(31个1)

    b)再对反码加1 1...1(32个1)10...0(31个0)

这样操作之后,结果就是2^64-2^31,恰好等于18446744071562067968,就对上了。

但是这个并不是我们需要的,我们要得到的是2147483648,怎么办呢?

unsigned long long v = abs((long long)INT_MIN) 这样的结果是2147483648。

这个过程是怎样的呢?

1)先在高位补上32个0,变成了0...0(32个零)10...0(31个零)

2)abs函数识别最高位为0,直接不变

这样v的取值就是2^31=2147483648,对上了。

补几个参考资料blog:

http://www.cnblogs.com/lknlfy/archive/2013/04/02/2996320.html

============================================

第二次过这道题,按照第一次的思路coding,改了几个corner case,最后AC了,代码比第一次要简洁清晰很多。

class Solution {
public:
int divide(int dividend, int divisor) {
// corner cases
if ( divisor== ) return dividend>= ? INT_MAX : INT_MIN;
if ( dividend== ) return ;
if ( dividend==INT_MIN && divisor==- ) return INT_MAX;
int sign = ;
sign = divisor>= ? sign : -sign;
sign = dividend>= ? sign : -sign;
unsigned long long n = abs((long long)dividend);
unsigned long long d = abs((long long)divisor);
if ( n<d ) return ;
if ( n==d ) return sign;
// bit manipulation simluate decimal
unsigned long long ret = ;
unsigned long long base = ;
while ( base*d<n ) base = base<<;
while ( base>= )
{
if ( base*d<=n )
{
ret += base;
n = n - base*d;
}
base = base >> ;
}
return ret*sign;
}
};

最新文章

  1. 基于AngularJS的企业软件前端架构[转载]
  2. chrome浏览器 模拟访问移动端
  3. quartz_job
  4. asp.net mvc 外网获取不到port问题解决
  5. Java性能优化权威指南-读书笔记(二)-JVM性能调优-概述
  6. Segment Tree 扫描线 分类: ACM TYPE 2014-08-29 13:08 89人阅读 评论(0) 收藏
  7. hdu 4640 Island and study-sister
  8. Docker 用法总结之:管理工具 shipyard 的具体使用指南
  9. js中的IP格式正则匹配校验详解~
  10. HDU3488 Tour [有向环覆盖 费用流]
  11. SDP(11):MongoDB-Engine功能实现
  12. 从零开始学习iftop流量监控(找出服务器耗费流量最多的ip和端口)
  13. [数分提高]2014-2015-2第6教学周第1次课讲义 3.3 Taylor 公式
  14. linuxDNS
  15. python 获取gearbest地址库代码
  16. Linux yum源配置
  17. 目标检测技术演进:R-CNN、Fast R-CNN、Faster R-CNN
  18. 关于文件的INode与Java中的文件操作接口
  19. Makefile编写 三 伪目标的作用
  20. 解决mysql远程登录

热门文章

  1. 153. Find Minimum in Rotated Sorted Array(leetcode, binary search)
  2. QT学习之QPair类
  3. 解决Zend加密的PHP页面出现Incompatible file format的问题
  4. POJ-3126 Prime Path---BFS+素数打表
  5. NYOJ(325)+NYOJ(456),01背包
  6. [转] JAVA中读取网络中的图片资源导入到EXCEL中
  7. CUDA 纹理内存
  8. 用纯css改变默认的radio和checkbox的样式
  9. Mantle--国外程序员最常用的iOS模型&amp;字典转换框架
  10. Linq to Entity 时间差作为筛选条件产生的问题