剑指 Offer 16. 数值的整数次方

原题:剑指 Offer 16. 数值的整数次方

浮点数误差问题

我们在判断底数xdouble类型)是否等于0的时候,不能直接写x==0,这是因为计算机在表示浮点数的时候存在误差。我们不能用等号判断两个小数是否相等。如果两个小数的差的绝对值很小,就可以认为他们相等。具体的原因可以参考这篇文章:浮点型变量的误差问题

方法一:基础解法

首先考虑会出现错误的情况,当底数base=0时,指数为负数,取倒数后分母为0,所以是一种错误的情况,应该在程序当中给出提示。

其他情况就可以考虑共用一个累乘函数,如果指数是负数,首先将指数取绝对值,再使用累乘函数得到结果。将结果再取倒数就能得到正确的答案。

class Solution {
public:
    bool errorFlag=false;
  
    double Power(double base, int exponent) {
      errorFlag=false;
      double res;
      if(exponent<0 && myequal(base,0.0)) {
          errorFlag=true;   	//使用flag与其他正常返回结果0.0的情况区分开
          return 0.0;
        }      
      unsigned int exp=(unsigned int)exponent;
      if(exponent<0) exp=(unsigned int)-exponent;
      res=myPower(base,exp);
      if(exponent<0) return 1.0/res;
      return res;
    }
  
    double myPower(double base,int exp){
      double res=1.0;   //如果指数exp=0,直接返回1.0,不会进入循环。
      for(int i=0;i<exp;i++){
        res *= base;
      }
      return res;
    }
  
    bool myequal(double num1,double num2){
      if((num1-num2)<0.0000001 && (num1-num2)>-0.0000001) return true;
      else return false;
    }
};

但是这种解法在LeetCode上是行不通的,因为它的时间复杂度为O(n),一个测试用例

1.00000
2147483647

就能让程序超出时间限制。

方法二:快速幂法

快速幂法可将时间复杂度降为O(logn),解法参考自:剑指 Offer 16 题目解析
推导过程:
x n = x n / 2 × x n / 2 = ( x 2 ) n / 2 x^n = x^{n/2} ×x^{n/2} = (x^2)^{n/2} xn=xn/2×xn/2=(x2)n/2
令 n/2 为整数,则n需要分奇偶数讨论:

x n = { ( x 2 ) n / / 2 , if  n  is even x ( x 2 ) n / / 2 , if  n  is odd x^n= \begin{cases} (x^2)^{n//2}, & \text {if $n$ is even} \\ x(x^2)^{n//2}, & \text{if $n$ is odd} \end{cases} xn={(x2)n//2,x(x2)n//2,if n is evenif n is odd

设res=1.0,则初始状态为 x n = x n × r e s x^n =x^n × res xn=xn×res

下面以 3^5为例进行推导:

循环 x n × ( r e s ) x^n × (res) xn×(res)
第0轮 3 5 × 1 3^5 × 1 35×1
第1轮 9 2 × 1 × 3 9^2 × 1 × 3 92×1×3
第2轮 8 1 1 × 1 × 3 81^1 × 1 × 3 811×1×3
第3轮 656 1 0 × 1 × 3 × 81 6561^0 × 1 × 3 × 81 65610×1×3×81

推导可得
3 5 = 656 1 0 × 1 × 3 × 81 = 1 × 1 × 3 × 81 3^5 =6561^0 × 1 × 3 × 81 =1 × 1 × 3 × 81 35=65610×1×3×81=1×1×3×81

class Solution {
public:
    double myPow(double x, int n) {
        //0的任何次方都为0;这里不考虑错误情况直接返回;
        if(myEqual(x,0.0)) {
            return 0.0;
        }
        double res=1.0;
        long b=n;
        if(b<0){
            x=1.0/x;
            b=-b;
        }
        while(b>0){
            if(b & 1) res *=x;  //如果指数为奇数
            x*=x;	  //
            b >>= 1;  //除2向下取整操作
        }
        return res;
    }

    bool myEqual(double num1,double num2){
        if((num1-num2)<0.0000001 && (num1-num2)>-0.00000001) return true;
        else return false;
    }
};

复杂度分析:

  • 时间复杂度:O(logn)
  • 空间复杂度:O(1)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值