[LeetCode] 数学计算模拟类问题:加法,除法和幂,注意越界问题。题 剑指Offer,Pow(x, n) ,Divide Two Integers
引言
数学计算的模拟类题目,往往是要求实现某种计算(比如两数相除),实现的过程中会有所限定,比如不允许乘法等等。
这类题目首先要注意计算过程中本身的特殊情况。比如求相除,则必须首先反映过来除数不能为0。
其次要记得考虑负数的情况,如果计算范围不单单是整数,还要考虑double的比较方式。
最后要注意越界情况,这个是最容易犯错的,只能具体问题具体分析。
例题 1 不用"+ - * / "做加法
这道题来自于剑指Offer,为了归类,我把它放到了这里。
面试题 47(*),不用加减乘除做加法(位运算易想到,怎么用就是个技术活了)(附 不定义新变量前提下交换两数的方法)
例题 2 Pow(x, n)
Implement pow(x, n).
class Solution {
public:
double pow(double x, int n) {
}
};
这道题目我在 面试题 11,求double类型的n次幂(double数值的比较不能用==,求幂的logN复杂度方法) 中写过。
要注意的就是:
1) 0 的 0 次幂无意义。
2) 0的负数次幂无意义。
3) 所有非零数的 0次幂为1。
4) double x 判断是否为0时,不能用简单的 == 0判断,因为double类型总是存在误差。
实现,时间复杂度 log(n),"n"是函数中的参数n
class Solution {
public:
double pow(double x, int n) {
if(n == ) return ;
if(equal(x, 0.0)) return ;
return (n > ? powCore(x, n) : 1.0/powCore(x, -n));
}
private:
bool equal(double x, double y){
if((x-y) < 0.00001 && (x-y) > -0.00001) return true;
return false;
}
double powCore(double x, int n){
if(n == ) return ;
double tmp = pow(x, n/);
return tmp*tmp*(n& ? x : );
}
};
另一个不用递归直接迭代实现的版本:
class Solution {
public:
double pow(double x, int n) {
if(n == ) return ;
if(n < && (x < 0.000001 && x > -0.000001)){
if(n < ) return ( << );
}
bool pos = (n > );
unsigned int tmp = abs(n);
double res = 1.0;
while(tmp){
if(tmp&) res *= x;
tmp = tmp >> ;
x *= x;
}
return (pos ? res : (double)(1.0/res));
}
};
例题 3 Divide Two Integers
Divide two integers without using multiplication, division and mod operator.
class Solution {
public:
int divide(int dividend, int divisor) {
}
};
这道题相较于前一道稍复杂些。首先考虑divisor为0的情况,再考虑负数的情况。
接着考虑解体方法,由于乘除都不能用,只能用加法,而如果直接累加自然会超时。我的思路是定义一个长32的数组path[32],path[0] = divisor, path[i] = path[i-1] + path[i-1]。path[32]不一定全被填满,当计算出path[i] > dividend时,path[i] 就不会被记录。由于path[i] 有大于 dividend的可能,因此临时存储计算结果的数定义为long long。
然后用这个path[32] 去凑成dividend,相除结果其实就是凑得过程中 1 << i 的相加(i 是 path[] 的 index)。
第一版代码如下:
class Solution {
public:
int divide(int dividend, int divisor) {
if(divisor == ) return ;
if(dividend == ) return ;
bool minus1 = false, minus2 = false, minus = false;
if(divisor < ){
divisor = ( - divisor);
minus1 = true;
}
if(dividend < ){
dividend = ( - dividend);
minus2 = true;
}
minus = (minus1 ^ minus2); //结果的正负号, minus若为true,结果就添加负号。
if(dividend < divisor) return ;
long long cache = divisor;
int* path = new int[];
int ind = ;
for(; cache <= dividend; path[ind] = (int)cache, ++ind, cache += cache); //填充path[]
cache = path[--ind]; int res = << ind; //从path的最末尾开始凑dividend
while(ind >= ){
if(cache == dividend) return minus ? (-res) : res;
if(cache > dividend){
cache -= path[ind];
res -= << ind;
}
for(--ind; ind >= && cache < dividend; cache += path[ind], res += << ind);
}
return minus ? (-res) : res;
}
};
这版代码在执行 sln.divide(-1010369383, -2147483648) 出现错误。
原因在于 开始的
dividend = (0 - dividend);
补码表示下,int下限绝对值比上限绝对值大1。dividend = -2147483648时,0-dividend 结果并非是2147483648。因此dividend 和 divisor的绝对值应该用unsigned int 表示。
考虑到这一点,当dividend = -2147483648 时,res 和 path 也有越过 int上限的可能,因此它们应该定义为 unisgned int。
改进后的代码,改动了一些参数的 格式,这次AC了。
class Solution {
public:
int divide(int dividend, int divisor) {
if(divisor == ) return ;
if(dividend == ) return ;
bool minus1 = false, minus2 = false, minus = false;
unsigned int divd, divr;
if(divisor < ){
divr = ( - divisor);
minus1 = true;
}else{
divr = divisor;
}
if(dividend < ){
divd = ( - dividend);
minus2 = true;
}else{
divd = dividend;
}
minus = (minus1 ^ minus2); //结果的正负号, minus若为true,结果就添加负号。
if(divd < divr) return ;
long long cache = divr;
unsigned int* path = new unsigned int[];
int ind = ;
for(; cache <= divd; path[ind] = (unsigned int)cache, ++ind, cache += cache); //填充path[]
cache = path[--ind]; unsigned int res = << ind; //从path的最末尾开始凑dividend
while(ind >= ){
if(cache == divd) return minus ? (-res) : res;
if(cache > divd){
cache -= path[ind];
res -= << ind;
}
for(--ind; ind >= && cache < divd; cache += path[ind], res += << ind);
}
return minus ? (-res) : res;
}
};
[LeetCode] 数学计算模拟类问题:加法,除法和幂,注意越界问题。题 剑指Offer,Pow(x, n) ,Divide Two Integers的更多相关文章
- leetcode 338. Counting Bits,剑指offer二进制中1的个数
leetcode是求当前所有数的二进制中1的个数,剑指offer上是求某一个数二进制中1的个数 https://www.cnblogs.com/grandyang/p/5294255.html 第三种 ...
- 剑指offer 65. 不用加减乘除做加法(Leetcode 371. Sum of Two Integers)
剑指offer 65. 不用加减乘除做加法(Leetcode 371. Sum of Two Integers) https://leetcode.com/problems/sum-of-two-in ...
- LeetCode:“剑指 Offer”
LeetCode:"剑指 Offer" 刷题小菜鸡,花了几天时间做了一遍 LeetCode 上给出的 "剑指 Offer" 在此做一下记录 LeetCode主页 ...
- 剑指offer编程题Java实现——面试题12相关题大数的加法、减法、乘法问题的实现
用字符串或者数组表示大数是一种很简单有效的表示方式.在打印1到最大的n为数的问题上采用的是使用数组表示大数的方式.在相关题实现任意两个整数的加法.减法.乘法的实现中,采用字符串对大数进行表示,不过在具 ...
- [leetcode] 剑指 Offer 专题(一)
又开了一个笔记专题的坑,未来一两周希望能把<剑指Offer>的题目刷完
- 【剑指Offer】不用加减乘除做加法 解题报告(Java)
[剑指Offer]不用加减乘除做加法 解题报告(Java) 标签(空格分隔): 剑指Offer 题目地址:https://www.nowcoder.com/ta/coding-interviews 题 ...
- 剑指Offer——网易校招内推笔试题+模拟题知识点总结
剑指Offer--网易校招内推笔试题+模拟题知识点总结 前言 2016.8.2 19:00网易校招内推笔试开始进行.前天晚上利用大约1小时时间完成了测评(这个必须做,关切到你能否参与面试).上午利用2 ...
- 【Java】 剑指offer(65) 不用加减乘除做加法
本文参考自<剑指offer>一书,代码采用Java语言. 更多:<剑指Offer>Java实现合集 题目 写一个函数,求两个整数之和,要求在函数体内不得使用+.-.×. ...
- 剑指offer 66. 构建乘积数组(Leetcode 238. Product of Array Except Self)
剑指offer 66. 构建乘积数组 题目: 给定一个数组A[0, 1, ..., n-1],请构建一个数组B[0, 1, ..., n-1],其中B中的元素B[i] = A[0] * A[1] * ...
随机推荐
- oozie的shell-action中加入hive脚本命令启动执行shell同时操作hive,抛异常Container killed on request. Exit code is 143 Container exited with a non-zero exit code 143
使用oozie来调度操作,用shell的action执行命令,其中shell里包含着hive -e 操作执行时,oozie窗口报 WARN ShellActionExecutor: - SERVER[ ...
- GIT团队实战博客
项目要求 组长博客 遇到的困难及解决办法 组员1(组长):王彬 遇到的困难 在团队任务分工的时候没有充分照顾到所有人,导致队员们的工作量不均. 现场编程时间不够 解决办法 在此对组员们表示抱歉,由于 ...
- js中call(),apply(),以及prototype的含义
最近段时间主要学习前端去了,然而所遇到的一些问题我觉得有必要去深究一下 prototype: 1 js中有三种表达方法 类方法,属性方法,原型方法 function People(name) { th ...
- 各种GIT代码托管工具比较
bitbucket免费支持5个开发成员的团队创建无限私有代码托管库. GOES是一个由GO语音编写的自组GIT托管服务. gitorious 是一个基于GIT版本控制系统的WEB项目托管平台,基于RU ...
- "Scrum站立会议"浅析
目录 Scrum Scrum Meeting功能及要点 Scrum Meeting点评 Scrum 定义:是一种软件开发流程.它并不是一项技术,这种开发方式的主要驱动核心是人,它采用的是迭代式开发. ...
- 从装饰者模式的理解说JAVA的IO包
1. 装饰者模式的详解 装饰者模式动态地将责任附加到对象上.若要扩展功能,装饰者提供了比继承更有弹性 的替代方案. 装饰者模式设计类之间的关系: 其 中Component是一个超类,ConcreteC ...
- 在DBGrid中实现多选功能
1.首先把DBGrid->options-dgMulitSelect设为True. dgRowSelect也设为True,此属性设为true后,DBGrid将不能编辑,如何实现能否编辑代码如下 ...
- QoS专题-第3期-QoS实现之报文简单分类与标记
QoS实现之报文简单分类与标记 上一期专题我们讲到,MQC中的流分类可以实现报文的分类,流行为可以对报文进行重标记,从而实现对流量的精细化差分服务.而优先级映射则可以根据802.1p优先级.DSCP优 ...
- [BZOJ4553][HEOI2016]序列 CDQ分治
4553: [Tjoi2016&Heoi2016]序列 Time Limit: 20 Sec Memory Limit: 128 MB Description 佳媛姐姐过生日的时候,她的小伙 ...
- JavaWeb文件上传和下载
文件上传和下载在web应用中非常普遍,要在jsp环境中实现文件上传功能是非常容易的,因为网上有许多用java开发的文件上传组件,本文以commons-fileupload组件为例,为jsp应用添加文件 ...