🚩传送门:力扣题目

题目

实现 [LC]16. 数值的整数次方 - 图1 ,即计算[LC]16. 数值的整数次方 - 图2[LC]16. 数值的整数次方 - 图3 次幂函数(即,[LC]16. 数值的整数次方 - 图4)。不得使用库函数,同时不需要考虑大数问题。

示例 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/22 = 1/4 = 0.25

解题思路:二进制

正常我们求解 [LC]16. 数值的整数次方 - 图5我们会将[LC]16. 数值的整数次方 - 图6自己相乘 [LC]16. 数值的整数次方 - 图7次,速度太慢

我们不难到发现 [LC]16. 数值的整数次方 - 图8[LC]16. 数值的整数次方 - 图9[LC]16. 数值的整数次方 - 图10
对于 [LC]16. 数值的整数次方 - 图11,相比于将[LC]16. 数值的整数次方 - 图12自己相乘 [LC]16. 数值的整数次方 - 图13次,使用二进制自乘,只需要[LC]16. 数值的整数次方 - 图14次,[LC]16. 数值的整数次方 - 图15越大效果越好,当前 [LC]16. 数值的整数次方 - 图16是否相乘取决于[LC]16. 数值的整数次方 - 图17二进制当前位是[LC]16. 数值的整数次方 - 图18还是[LC]16. 数值的整数次方 - 图19
[LC]16. 数值的整数次方 - 图20

算法流程:

  1. [LC]16. 数值的整数次方 - 图21 时:直接返回 [LC]16. 数值的整数次方 - 图22 (避免后续 [LC]16. 数值的整数次方 - 图23 操作报错)。
  2. 初始化 [LC]16. 数值的整数次方 - 图24
  3. [LC]16. 数值的整数次方 - 图25 时:把问题转化至 [LC]16. 数值的整数次方 - 图26 的范围内,即执行 [LC]16. 数值的整数次方 - 图27[LC]16. 数值的整数次方 - 图28
  4. 循环计算:当 [LC]16. 数值的整数次方 - 图29 时跳出;

    • [LC]16. 数值的整数次方 - 图30 时:将当前 [LC]16. 数值的整数次方 - 图31 乘入 [LC]16. 数值的整数次方 - 图32 (即 [LC]16. 数值的整数次方 - 图33 );
    • 执行 [LC]16. 数值的整数次方 - 图34[LC]16. 数值的整数次方 - 图35
    • 执行 右移一位(即 [LC]16. 数值的整数次方 - 图36)。
  5. 返回 [LC]16. 数值的整数次方 - 图37

复杂度分析

时间复杂度:[LC]16. 数值的整数次方 - 图38,二分的时间复杂度为对数级别。

空间复杂度:[LC]16. 数值的整数次方 - 图39占用常数大小额外空间。

官方代码

  1. class Solution {
  2. public double myPow(double x, int n) {
  3. // 指数
  4. long ex=n;
  5. double res = 1;
  6. if(n<0){
  7. ex=-ex;
  8. x=1/x;
  9. }
  10. while (ex != 0) {
  11. if ((ex & 1) == 1) {
  12. res = res * x;
  13. }
  14. ex = ex >> 1;
  15. x = x * x;
  16. }
  17. return res;
  18. }
  19. }