剑指Offer--第16题 数值的整数次方

第16题 数值的整数次方

题目:给定一个double类型的浮点数base和int类型的整数exponent。求base的exponent次方。
思路 看到有点懵,第一感觉觉得是不是应该考虑0的0次或者负数情况,还有就是浮点类型没办法使用"="号,最后自己以偷懒的方式直接调用Java的API,如果面试题中不让调用库函数,那么基本上这题就是挂了可能。
以上题目描述来自牛客,没有对使用做限制。真正的剑指offer上有限制条件不得使用库函数,同时不需要考虑大数问题。

自己的low代码

public class Solution {
    public double Power(double base, int exponent) {
         return Math.pow(base, exponent);
  }
}

剑指offer思路::需要将所有情况考虑全面:base可为正、0和负,同样exponent也可以为正、0和负。1、当base为0,exponent为负时,这是一种常见的异常,分为为0异常;2、当exponent为0时;3、expoonent为负;4、考虑运行效率问题;
结果正确,但效率不高的写法:

public class Solution {
    public double Power(double base, int exponent) {
		if(base==0&&exponent<0) {
			return 0;
		}
		if(exponent==0) { //这样判断是合理的;
			return 1;
		}
		
        int ex = exponent;
		if(exponent<0){  //容易忽略;
			ex = -exponent;
		}
		double result = 1;
		for(int i=0;i<ex;i++ ) { //效率不高;
			result *= base;
		}
		if(exponent<0) {
			result=1/result;
		}
		return result;
    
	  }
}

问题:除了使用for循环外,还有就是double为0等号的使用,之前一直有一个错觉就是浮点类型不能使用等号判断,因为不准确,所以对这种写法第一反应就是不正确。但是看了看了网上的解释发现,其实这种写法有道理的,因为

回复于 2013-11-27 09:55:46 #5 得分:5
首先一个 double 是否为 0,或者其他的数值,是精确的,可以使用== 。
比如 double f = 0; 此时 f 是精确为 0 ,f == 0 为 true。
但是,double 在运算中,由于截尾的原因,总是有误差的。而此时是否为0,要看你的这个运算的精度要求。
比如运算后,f = 0.001,此时不能简单去和 e 去比较。

简单来说,就是如果你所要比较的那个值如果是精确的那么比较就是精确的,如果本身存在截取,那么使用就不正确。
对for循环进行改进

public class Solution {
    public double Power(double base, int exponent) {
		if(base==0&&exponent<0) {
				return 0;
			}
			int ex = exponent;
			if(exponent<1){
				ex = -exponent;
			}
			double result = Power3(base,ex);
			if(exponent<0) {
				result=1/result;
			}
			
			
			return result;
		  }
		public double Power3(double base, int exponent) {
			if(exponent ==0 ) {
				return 1;
				
			}
			if(exponent==1) {
				return base;
			}
			double result = Power3(base,exponent>>1);
			result *=result;
			if((exponent&1)==1) {//奇偶判断
				result *=base;
				
			}
			
			return result;
		}
}

优雅写法

链接:https://www.nowcoder.com/questionTerminal/1a834e5e3e1a4b7ba251417554e07c00
来源:牛客网

/**
 * 1.全面考察指数的正负、底数是否为零等情况。
 * 2.写出指数的二进制表达,例如13表达为二进制1101。
 * 3.举例:10^1101 = 10^0001*10^0100*10^1000。
 * 4.通过&1和>>1来逐位读取1101,为1时将该位代表的乘数累乘到最终结果。
 */
public double Power(double base, int n) {
    double res = 1,curr = base;
    int exponent;
    if(n>0){
        exponent = n;
    }else if(n<0){
        if(base==0)
            throw new RuntimeException("分母不能为0"); 
        exponent = -n;
    }else{// n==0
        return 1;// 0的0次方
    }
    while(exponent!=0){
        if((exponent&1)==1)
            res*=curr;
        curr*=curr;// 翻倍
        exponent>>=1;// 右移一位
    }
    return n>=0?res:(1/res);       
}

posted @ 2018-07-09 13:20  LynnMin  阅读(180)  评论(0编辑  收藏  举报