[LeetCode] 数学计算模拟类问题:除法和幂,注意越界问题。题 Pow(x, n) ,Divide Two Integers

引言


数学计算的模拟类题目,往往是要求实现某种计算(比如两数相除),实现的过程中会有所限定,比如不允许乘法等等。

这类题目首先要注意计算过程中本身的特殊情况。比如求相除,则必须首先反映过来除数不能为0。

其次要记得考虑负数的情况,如果计算范围不单单是整数,还要考虑double的比较方式。

最后要注意越界情况,这个是最容易犯错的,只能具体问题具体分析。

例题 1 Pow(x, n)


Implement
pow(xn).


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 == 0) return 1;
if(equal(x, 0.0)) return 0;
return (n > 0 ? 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 == 0) return 1;
double tmp = pow(x, n/2);
return tmp*tmp*(n&1 ? x : 1);
}
};

例题 2 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 == 0) return 0;
if(dividend == 0) return 0;

bool minus1 = false, minus2 = false, minus = false;
if(divisor < 0){
divisor = (0 - divisor);
minus1 = true;
}
if(dividend < 0){
dividend = (0 - dividend);
minus2 = true;
}
minus = (minus1 ^ minus2); //结果的正负号, minus若为true,结果就添加负号。

if(dividend < divisor) return 0;
long long cache = divisor;
int* path = new int[32];
int ind = 0;
for(; cache <= dividend; path[ind] = (int)cache, ++ind, cache += cache); //填充path[]
cache = path[--ind]; int res = 1 << ind; //从path的最末尾开始凑dividend
while(ind >= 0){
if(cache == dividend) return minus ? (0-res) : res;
if(cache > dividend){
cache -= path[ind];
res -= 1 << ind;
}
for(--ind; ind >= 0 && cache < dividend; cache += path[ind], res += 1 << ind);
}
return minus ? (0-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 == 0) return 0;
if(dividend == 0) return 0;

bool minus1 = false, minus2 = false, minus = false;
unsigned int divd, divr;
if(divisor < 0){
divr = (0 - divisor);
minus1 = true;
}else{
divr = divisor;
}
if(dividend < 0){
divd = (0 - dividend);
minus2 = true;
}else{
divd = dividend;
}
minus = (minus1 ^ minus2); //结果的正负号, minus若为true,结果就添加负号。

if(divd < divr) return 0;
long long cache = divr;
unsigned int* path = new unsigned int[32];
int ind = 0;
for(; cache <= divd; path[ind] = (unsigned int)cache, ++ind, cache += cache); //填充path[]
cache = path[--ind]; unsigned int res = 1 << ind; //从path的最末尾开始凑dividend
while(ind >= 0){
if(cache == divd) return minus ? (0-res) : res;
if(cache > divd){
cache -= path[ind];
res -= 1 << ind;
}
for(--ind; ind >= 0 && cache < divd; cache += path[ind], res += 1 << ind);
}
return minus ? (0-res) : res;
}
};

[LeetCode] 数学计算模拟类问题:除法和幂,注意越界问题。题 Pow(x, n) ,Divide Two
Integers

时间: 2024-10-15 10:36:15

[LeetCode] 数学计算模拟类问题:除法和幂,注意越界问题。题 Pow(x, n) ,Divide Two Integers的相关文章

LeetCode开心刷题十六天——29. Divide Two Integers*

From now on,I grade the questions I've done,* less means more difficult *** done by myself **need see answer,but I can reappear it *need see answer&hard to reappear 29. Divide Two Integers Medium 7003349FavoriteShare Given two integers dividend and d

理工科应该的知道的C/C++数学计算库(转)

理工科应该的知道的C/C++数学计算库(转) 作为理工科学生,想必有限元分析.数值计算.三维建模.信号处理.性能分析.仿真分析...这些或多或少与我们常用的软件息息相关,假如有一天你只需要这些大型软件系统的某一个很有限的功能,你是不是也要因此再用一用那动辄几个g的软件呢?其实我觉得如果系统不是很大,不是很复杂,我们个人完全有可能自己去编写代码来实现这些‘’有限的功能‘’.别以为这是件很困难的事情,我总以为大学期间学的c语言是极其有用的,只要你会基本的c语言语法,你就可以的. 下面我来介绍几个非常

4 个用于执行高级数学计算的 JavaScript 库

在使用JavaScript执行数学方面的任务时,往往要用到浮点运算,且需要精确到某位小数,这就容易造成错误,而且会相当费时.因此,如果你需要做一些高精度的数学计算的编程工作,比如财务或科学计算,那么你一定需考虑使用下面的这些库. 1.  numbers.js numbers.js提供了大量的.可用于服务器端的数学功能,你可以用它来执行下面这些任务: 基本计算(如两数相加) 复数 微积分 数字信号处理(DSP) 矩阵运算 素数计算 统计 迭代计算(如斐波那契数列) 要使用numbers.js,你首

[笔记]shell编程:数学计算

在shell Script中,有好几种进行数学运算的方法,虽然有几个效果差不多,在编写程序的时候使用一种方法就够了,但是我们可能还需要学习别人的程序啊,在阅读别人的程序的时候不能不认识这些东西吧.所以,留个笔记. 一.expr 命令  --  expr 允许在命令行上处理数学表达式,但是略显拙劣. 例:$ expr 1 + 5    #注意在表达式中要有空格,如果写成1+5那么结果就不是我们想要的了. expr命令能够识别一些不同的数学和字符串操作符: 操作符 描述 arg1 | arg2 如果

数字(数学)操作类 Math Random 类 ,大数字操作类

Math 提供了大量的数学操作方法 Math类中所有的方法都是static 方法 重点看这个操作,四舍五入 System.out.println(Math.round(-16.5)) ; -16 System.out.println(Math.round(16.5)) ; 17 大于等于0.5进位. Random类 取得随机数的类 java.util 包 产生100之内的随机整数 Random rand = new Random() ; for(int x = 0 ; x < 10 ; x ++

dx11 入门 Tutorial 04: DX、HLSL中矩阵的内存存储和数学计算方式 DirectXSampleBrowser(June 2010)

主要是两方面: 1.shader数据和dx的通信,使用constant Buffer 2.矩阵的数学计算方式和内存存储方式再DX和HLSL中的异同 先说第一个: dx中的常量数据matrix等传入shader中流程: The first thing that we need to do is declare three constant buffer variables. Constant buffers are used to store data that the application n

js模拟类

ECMAScript6已经支持了class,但之前版本都不支持类,但是可以通过一些方法来模拟类. js中的类,既是重点,也是难点,很多时候都感觉模棱两可. 首先强调一下js中很重要的3个知识点:this.prototype.constructor. 下面我们来总结一下定义(模拟)类的几种方法: 1.工厂模式 ? 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 function createObject(name,age){   var obj = new Objec

精确计算工具类,提供加减乘除的计算

package com.ljq.util; import java.math.BigDecimal; /** * 精确计算工具类,提供加减乘除的计算 * * @author jqlin */ public class CompuUtils { /**小数点后保留的位数*/ public final static int SCALE = 5; /** 0 */ public final static int ZERO = 0; /** * BigDecimal大小比较 * * @param a *

洛谷P1290 欧几里德的游戏 数学 博弈论 模拟

洛谷P1290 欧几里德的游戏 数学 博弈论 模拟 这道题我们因为当 x 大于 y 时 你也只能在合法范围 内取 1 个 y 两个 y 也就是说 能取的y大于等于2时,则你本质不同的取法共有两种,此时你必定获胜,因为本质不同,而在最优策略下,则说明胜利者也不同,也就是说这时候你可以决定自己的输赢 ,我们称这种必胜局为 v 局 2.但是如果 v 局后面还有v 局怎么办,这个不必担心,因为先拿到 v局的人,有两种本质不同的取法,也就是说 他可以控制自己下次必定拿到 v 局,这样就 能确保胜利了 所以