基本知识概述
public double Power(double base, int exponent) {
if(exponent ==0){
return 1;
}
if(base ==0){
return 0;
}
if(base ==0 || exponent ==0){
return 1;
}
if(exponent < 0){
base = 1/base;
exponent = -exponent;
}
return base*Power(base,exponent-1);
}
通常我们有3 种方式把错误信息传递给函数的调用者。
第一种方式是函数用返回值来告知调用者是否出错。比如很多Windows的 AP[就是这个
类型。在 Windows中,很多API的返回值为0 表示API调用成功,而返回值不为0 表示在API的调用过程中出错了。微软为不同的非零返回值定义了不同的意义,调用者吋以根据这些返回值判断出错的原因。这种方式最大的问题是使用不便,因为函数不能直接把计算结果通过返回值赋值给其他变量,同时也不能把这个函数计算的结果直接作为参数传递给其他函数。
第二种方式是当错误发生时设置一个全局变量。此时我们可以在返回值中传递计算结果了。这种方法比第一种方法使用起来更加方便,因为调用者可以直接把返回值赋值给其他变量或者作为参数传递给其他函数。Windows的很多API运行出错之后,也会设置一个全局变量。我们可以通过调用函数GetLastError分析这个表示错误的全局变量,从而得知出错的原
因.但这种方法有一个问题:调用者很容易忘记检查全局变歐,因此在调用出错的时候忘记进行相应的错误处理,从而留下安全隐患。
第三种方式是异常。当函数运行出错的时候,我们就抛出一个异常,还可以根据不同的出错原因定义不同的异常类型。因此,函数的调用者根据异常的类型就能知道出错的原因,从而做出相应的处理。另外,我们能显式划分程序正常运行的代码块(h 7 模块)和处理异常的代码块(catch模块),逻辑比较清晰。异常在髙级语言如C#中是强烈推荐的错误处理方式,
但有些早期的语言如C 语言还不支持异常。另外,在抛出异常的时候,程序的执行会打乱正常的顺序,对程序的性能有很大的影响。上述3 种错误处理的方式各有其优缺点,如表3.1所示。那么,面试的时候我们该采用哪种方式呢?这要看面试官的需求。在听到面试官的题目之后,我们要尽快分析出可能存在哪些非法的输入,并和面试官讨论该如何处理这些非法输入。
题目
给定一个double类型的浮点数base和int类型的整数exponent。求base的exponent次方。
注意
1 当指数为负数的时候,可以先对指数求绝对值,然后算出次方的结果之后再取倒数。如果底数为0,则直接返回0。此时的次方在数学上是没有意义的。
2 面试官会问如果输入的指数(exponent) 小于1 (零和负数)的时候怎么办?上面的
代码完全没有考虑,只考虑了指数是正数的情况。
3 前面提到我们可以采用3 种方法:返回值、全局变量和异常。面试的时候可以向面试官阐述每种方法的优缺点,然后一起讨论决定选用哪种方法
4 除此之外,我们要注意:由于计算机表示小数(包括float和double型小数)都有误差,我们不能直接用等号(==)判断两个小数是否相等。如果两个小数的差的绝对值很小,比如小于0.0000001,就可以认为它们相等。
在计算次方的时候,除了简单的遍历,我们可以使用如下公式进行计算,来减少计算量:
5 既全面又高效的解法,确保我们能拿到 Offer如果输入的指数exponent为 32,则在函数PowerWithUnsignedExponent的循环中需要做31次乘法。但我们可以换一种思路考虑:我们的目标是求出一个数字的32次方,如果我们己经知道了它的16次方,那么只要在16次方的基础上再平方一次就可以了。而 16次方是8 次方的平方。这样以此类推,我们求32次方只需要做5 次乘法:先求平方,在平方的基础t 求 4次方,在 4 次方的基础上求8 次方,在 8 次方的基础卜.求16次方,最后在16次方的基础上求32次方。
6 最后再提醒一个细节:我们用右移运算符代替了除以2 , 用位与运算符代替了求余运算符(%)来判断一个数是奇数还是偶数。位运算的效率比乘除法及求余运算的效率要高很多。既然耍优化代码,我们就把优化做到极致。在面试的时候,我们可以主动提醒面试官注意代码中的两处细节(判断base是否等于0 和用位运算代替乘除法及求余运算),让他知道我们对编程的细节很重视。细节很重要,因为细节决定成败,一两个好的细节说不定就能让面试官下定决心给我们Offer。
/**
* 方法1:常规解法,时间复杂度为O(N)
* @param base
* @param exponent
* @return
*/
public static double Power(double base, int exponent) {
if(base==0&&exponent<0){
throw new RuntimeException();
}
if(base==0)
return 0;
int n=Math.abs(exponent);
if(n==0)
return 1;
if(n==1)
return base;
double result = 1.0;
for(int i = 1;i<=Math.abs(exponent);i++){
result *= base;
}
return exponent>0?result:1/result;
}
/**
* 方法2:递归解法,时间复杂度为O(logN)
* @param base
* @param exponent
* @return
*/
public static double PowerEst(double base, int exponent) {
if(base==0&&exponent<0){
throw new RuntimeException();
}
if(base==0)
return 0;
int n=Math.abs(exponent);
if(n==0)
return 1;
if(n==1)
return base;
double result=PowerEst(base,n>>1);
result*=result;
if((n&1)==1)
result*=base;
if(exponent<0)
result=1/result;
return result;
}
LeetCode
你的任务是计算 ab 对 1337 取模,a 是一个正整数,b 是一个非常大的正整数且会以数组形式给出。
示例 1:
输入: a = 2, b = [3]
输出: 8
示例 2:
输入: a = 2, b = [1,0]
输出: 1024
思路
ten_power 存储a^(10*(length-1-i))%1337的值以便后续计算。
对于b[i]处的求解,根据(a^ten_power)^b[i],从后往前逐个计算b数组中的次方.
public int binaryPow(int a, int n) {
if (n == 0) {
return 1;
}
int h = binaryPow(a, n / 2);
if (n % 2 == 0) {
return (h * h) % 1337;
} else {
// 此处务必两次mod,因为h*h*a的话,以最坏情况1336^3计算,是会超过Integer.MAX_VALUE的
return ((h * h) % 1337) * a % 1337;
}
}
public int superPow(int a, int[] b) {
int rst = 1;
int ten_power = 0, len = b.length, i_power = 0;
if (a == 1) {
return a;
}
a = a % 1337;
ten_power = a;
for (int i = b.length - 1; i >= 0; i--) {
i_power = binaryPow(ten_power, b[i]);
rst = (rst * i_power) % 1337;
ten_power = binaryPow(ten_power, 10);
}
return rst;
}