【Divided Two】cpp
题目:
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;
}
};
【Divided Two】cpp的更多相关文章
- hdu 4739【位运算】.cpp
题意: 给出n个地雷所在位置,正好能够组成正方形的地雷就可以拿走..为了简化题目,只考虑平行于横轴的正方形.. 问最多可以拿走多少个正方形.. 思路: 先找出可以组成正方形的地雷组合cnt个.. 然后 ...
- Hdu 4734 【数位DP】.cpp
题意: 我们定义十进制数x的权值为f(x) = a(n)*2^(n-1)+a(n-1)*2(n-2)+...a(2)*2+a(1)*1,a(i)表示十进制数x中第i位的数字. 题目给出a,b,求出0~ ...
- 【Valid Sudoku】cpp
题目: Determine if a Sudoku is valid, according to: Sudoku Puzzles - The Rules. The Sudoku board could ...
- 【Permutations II】cpp
题目: Given a collection of numbers that might contain duplicates, return all possible unique permutat ...
- 【Subsets II】cpp
题目: Given a collection of integers that might contain duplicates, nums, return all possible subsets. ...
- 【Sort Colors】cpp
题目: Given an array with n objects colored red, white or blue, sort them so that objects of the same ...
- 【Sort List】cpp
题目: Sort a linked list in O(n log n) time using constant space complexity. 代码: /** * Definition for ...
- 【Path Sum】cpp
题目: Given a binary tree and a sum, determine if the tree has a root-to-leaf path such that adding up ...
- 【Symmetric Tree】cpp
题目: Given a binary tree, check whether it is a mirror of itself (ie, symmetric around its center). F ...
随机推荐
- java集合框架——Set
一.Set概述 Set集合的特点是元素不允许重复,而且是无序的(添加和取出的顺序不一致). Set接口中的方法和Collection接口中的方法几乎相同,略. Set接口下常用的两个类:HashSet ...
- Xcode SDK模拟器安装及安装路径
将SDK想要装的版本,将SDK包放入‘mac中的SDK安装路径’.再将Xcode模拟器重启. 再打开Xcode模拟器,就可以在菜单栏的 ‘硬件’->’设备‘->’iPhone Retina ...
- 基于ASP.NET WPF技术及MVP模式实战太平人寿客户管理项目开发(Repository模式)
亲爱的网友,我这里有套课程想和大家分享,假设对这个课程有兴趣的.能够加我的QQ2059055336和我联系. 课程背景 本课程是教授使用WPF.ADO.NET.MVVM技术来实现太平人寿保险有限公司 ...
- [Pytorch] pytorch笔记 <三>
pytorch笔记 optimizer.zero_grad() 将梯度变为0,用于每个batch最开始,因为梯度在不同batch之间不是累加的,所以必须在每个batch开始的时候初始化累计梯度,重置为 ...
- 问题 C: B 统计程序设计基础课程学生的平均成绩
题目描述 程序设计基础课程的学生成绩出来了,老师需要统计出学生个数和平均成绩.学生信息的输入如下: 学号(num) 学生姓名(name) ...
- 奇异值分解(SVD)原理及应用
一.奇异值与特征值基础知识: 特征值分解和奇异值分解在机器学习领域都是属于满地可见的方法.两者有着很紧密的关系,我在接下来会谈到,特征值分解和奇异值分解的目的都是一样,就是提取出一个矩阵最重要的特征. ...
- CCF CSP 201712-2 游戏
题目链接:http://118.190.20.162/view.page?gpid=T67 问题描述 有n个小朋友围成一圈玩游戏,小朋友从1至n编号,2号小朋友坐在1号小朋友的顺时针方向,3号小朋友坐 ...
- MySQL 存储过程参数IN OUT INOUT区别
MySQL 存储过程参数IN OUT INOUT对比 一.IN -- 创建测试存储过程 delimiter // create procedure p_in ( IN num int ) begin ...
- 《JavaScript高级程序设计第三版》——细碎知识痛点整理(第六章)
面向对象的程序设计 对象是一组没有特定顺序的值6.1.1 属性类型ECMAScript中有两种属性:数据属性和访问器属性.1. 数据属性Configurable 表示能否通过delete删除属性从而重 ...
- 关于 export default 和 export
// 第一组 export default function crc32() { // 输出 // ... } import crc32 from 'crc32'; // 输入 // 第二组 expo ...