(分治) 剑指 Offer 16. 数值的整数次方 ——【Leetcode每日一题】

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

难度:中等

实现 pow(x, n) ,即计算 xn 次幂函数(即, x n x^n xn)。不得使用库函数,同时不需要考虑大数问题。

示例 1:

输入:x = 2.00000, n = 10
输出:1024.00000

示例 2:

输入:x = 2.10000, n = 3
输出:9.26100

示例 3:

输入:x = 2.00000, n = -2
输出:0.25000
解释: 2 − 2 = 1 / 2 2 = 1 / 4 = 0.25 2^{-2} = 1/2^2 = 1/4 = 0.25 22=1/22=1/4=0.25

提示

  • − 100.0 < x < 100.0 -100.0 < x < 100.0 100.0<x<100.0
  • − 2 31 < = n < = 2 31 − 1 -2^{31} <= n <= 2^{31}-1 231<=n<=2311
  • n 是一个整数
  • 要么 x 不为零,要么 n > 0
  • − 1 0 4 < = x n < = 1 0 4 -10^4 <= x^n <= 10^4 104<=xn<=104

注意:本题与 50. Pow(x, n) 相同。

思路:分治

最直观的解法是将 x 重复乘 n 次,x*x*x...*x,那么时间复杂度为 O ( N ) O(N) O(N)

因为乘法是可交换的,所以可以将上述操作拆开成两半 (x*x..*x)* (x*x..*x),两半的计算是一样的,因此只需要计算一次。而且对于新拆开的计算,又可以继续拆开。

这就是 分治思想,将原问题的规模拆成多个规模较小的子问题,最后子问题的解合并起来。

本题中子问题是 x n / 2 x^{n/2} xn/2,在将子问题合并时将子问题的解乘于自身相乘即可。

  • 但如果 n 不为偶数,那么拆成两半还会剩下一个 x,在将子问题合并时还需要需要多乘于一个 x
    x n = { x n / 2 ∗ x n / 2 n % 2 = 0 x ∗ ( x n / 2 ∗ x n / 2 ) n % 2 = 1 x^n=\left\{\begin{array}{rl}x^{n/2}*x^{n/2}&\quad n\%2=0\\x*(x^{n/2}*x^{n/2})&\quad n\%2=1\end{array}\right. xn={xn/2xn/2x(xn/2xn/2)n%2=0n%2=1

因为 ( x ∗ x ) n / 2 (x*x)^{n/2} (xx)n/2 可以通过递归求解,并且每次递归 n 都减小一半,因此整个算法的时间复杂度为 O ( l o g N ) O(logN) O(logN)

代码:(C++、Java)

方法一:快速幂 + 递归
C++

class Solution {
private:
    double pow(double x, long n){
        if(n == 0) return 1;
        if(n == 1) return x;
        if(n % 2 == 0) return pow(x * x, n / 2);
        return x * pow(x * x, n / 2);
    }
public:
    double myPow(double x, int n) {
        long long N = n < 0 ? -(long long)n : n; 
        double ans = pow(x, N);
        return n < 0 ? 1 / ans : ans;
    }
};

Java

class Solution {
    private double pow(double x, long n){
        if(n == 0) return 1;
        if(n == 1) return x;
        if(n % 2 == 0) return pow(x * x, n / 2);
        return x * pow(x * x, n / 2);
    }
    public double myPow(double x, int n) {
        long N = n < 0 ? -(long)n : n; 
        double ans = pow(x, N);
        return n < 0 ? 1 / ans : ans;
    }
}

方法二:快速幂 + 迭代
C++

class Solution {
public:
    double myPow(double x, int n) {
        if(n == 0) return 1;
        if(n == 1) return x;
        long long N = n < 0 ? -(long long)n : n;
        double ans = 1;
        while( N != 1){
            if(N % 2 != 0) ans *= x;
            x *= x;
            N /= 2;
        }
        ans *= x;
        return n < 0 ? 1.0 / ans : ans;
    }
};

Java

class Solution {
    public double myPow(double x, int n) {
        if(n == 0) return 1;
        if(n == 1) return x;
        long N = n < 0 ? -(long)n : n;
        double ans = 1;
        while( N != 1){
            if(N % 2 != 0) ans *= x;
            x *= x;
            N /= 2;
        }
        ans *= x;
        return n < 0 ? 1.0 / ans : ans;
    }
}

运行结果:

(分治) 剑指 Offer 16. 数值的整数次方 ——【Leetcode每日一题】_第1张图片

复杂度分析:

  • 时间复杂度 O ( l o g n ) O(logn) O(logn),即为对 n 进行二进制拆分的时间复杂度。
  • 空间复杂度 O ( 1 ) O(1) O(1);法一递归的函数调用会使用栈空间所以复杂度为 O ( l o g n ) O(logn) O(logn)

题目来源:力扣。

放弃一件事很容易,每天能坚持一件事一定很酷,一起每日一题吧!
关注我LeetCode主页 / CSDN—力扣专栏,每日更新!

注: 如有不足,欢迎指正!

你可能感兴趣的:(LeetCode,leetcode,算法,职场和发展)