• 牛客网剑指offer第12题——数值的整数次方


    题目:

    给定一个double类型的浮点数base和int类型的整数exponent。求base的exponent次方。保证base和exponent不同时为0。
    初次拿到这个题目,我们当然知道采用累乘的方法。但是傻子都知道这种做法,时间复杂度自然是O(n)级别的。有没有更为简单的做法呢?
    有的,那就是快速幂。
    快速幂

    求 x 的 n 次方
    当然,这道题你也可以采用 n 次循环让 n 个 x 相乘,不过,这样的做法毫无意义,因为估计小学生也会做。

    不过这道题如果知道了思路,还是挺简单,我举个例子吧,例如我们要求 2^8。

    1、首先,我们可以通过 2 * 2 = 4 得到 2^2

    2、接着,我们利用刚才的结果,让 4 * 4 = 16 得出 2^4

    3、接着,同样的道理,让 16 * 16 = 256 得出 2^8

    通过这种方法,只需要三次相乘即可得出,也就是说,我们可以在 O(logn) 的时间复杂度求出 x 的 n 次方。这种方法的思想,我们也称之为快速幂思想,和二分查找的思想有点类型,每次都进行翻倍或者缩小一半。

    这个时候有人可以能会问,如果 n = 8 或者 n = 16 ,由于 n 是 2 的幂次方,所以可以按照你上面的方法做,那如果 n = 12 呢?

    其实道理是一样的,我们可以对 12 进行拆分啊,把 12 拆分成 12 = 4 + 8 就可以了。然后就有 2^12 = 2^4 * 2^8。

    那如果 n = 13 呢,也是一样的,拆分成 13 = 1 + 4 + 8,即 2^13 = 2^1 * 2^4 * 2^8。

    也就是说,任何整数,都可以把它拆分成若干个 2 的幂次方进行相加。
    这也是一种很常见的思想,我当时也想到了这种方法,但终究无法写出代码,究其原因是对于位运算的不熟练导致的。

    快速幂额核心思想是什么:任意整数指数表示成2的幂次的和,而快速幂算法中我们可以通过对整数的移位表征这种关系。

    比如9 = 23+20,因此,当我们要求59的的时候,我们会想到59=5(8+1)=58×51。但在实际中,又该怎么表示这种关系呢。这个时候我们就要用到位运算了。为何?9 = 1001(二进制)。因此,我们可以通过对指数的二进制处理。来进行操作。

    来看代码:

     1 int fastPower(int base, int exponent) {
     2     int sum = 1;
     3     while (exponent != 0) {
     4         if ((exponent & 1) != 0) {
     5             sum *= base;
     6         }
     7         exponent = expnonent >> 1;  // 对指数进行移位
     8         base *= base;               // 让base的次幂以2的倍数增长
     9     }
    10     return sum;
    11 }

    代码十分的简洁。我们可以看到的是。第7行的代码完成了对指数的移位运算。而这个移位运算的作用,就是将2的整数次幂给剥离出来。还需要注意的是&是按位与的意思。因此num&1是判断num的二进制形式的最后一位是否为1.

    以上述代码为例子,求59,看会发生什么?

    9 = 1001(二进制)-> (1001&1) == 1->sum = 1*5=5;

    1001>>1 = 100;base = 5*5 (25)

    下一次循环:

    100&1 == 0->sum值不变;

    100>>1 = 10;base = (5*5)*(5*5);

    下一次循环:

    10&1 == 0->sum值不变;

    10>>1 = 1;base = ((5*5)*(5*5))*((5*5)*(5*5));

    下一次循环:

    1&1 = 1->sum = sum*base = 5*((5*5)*(5*5))*((5*5)*(5*5)) = 51*58=59

    我们可以看到的是9 = 1001 = 2^3+2^1。通过移位运算表示出来了。

    因此,此题最终代码为:

     1 class Solution {
     2 public:
     3     double Power(double base, int exponent) {
     4     double sum =1.0;
     5     unsigned int abs_exponent =abs(exponent);
     6     while(abs_exponent> 0)
     7     {
     8         if(abs_exponent&1 != 0)
     9         {
    10             sum *=base;
    11         }
    12         abs_exponent = abs_exponent>>1;
    13         base*=base;
    14     }
    15         if(exponent>=0)
    16             return sum;
    17         else
    18             return 1.0/sum;
    19     }
    20 };
  • 相关阅读:
    [转]Magento刷新索引的几种方法
    [转]centos7 移动mysql5.7.19 数据存储位置
    [转]解决Magento批量导入带图片的商品的问题
    [转]【mysql监控】查看mysql库大小,表大小,索引大小
    [转]Centos系统中查看文件和文件夹大小
    [转]Magento 2.2 Developer Documentation
    [转]Magento2开发教程
    [转]Magento Configurable Product
    [转]论magento1和magento2的速度性能优化问题
    [转]本地 Windows 计算机密码登录 登录 腾讯云 Linux 实例
  • 原文地址:https://www.cnblogs.com/shaonianpi/p/12703431.html
Copyright © 2020-2023  润新知