快速幂算法

快速幂算法

最后求出的幂结果实际上就是在变化过程中所有当指数为奇数时底数的乘积。

1、没用快速幂的时候

就是在对一个数做幂运算的时候,比如说求2^10,一般我们是用循环做

  • 如果幂大于0,我们直接算
  • 如果等于0,我们直接return 1
  • 如果小于0,我们先算大于0的情况,在求倒数
public long pow(long base, long power) {
    long result = 1;
    if(power == 0) return 1;
    boolean flag = true;
    if(power < 0) flag = false;
    for(long i = 0; i < power; i++) {
      result = result * base;
    }
    return flag ? result : 1 / result;
}

这个算法的时间复杂度很简单是O(n)级别的,但是如果用快速幂算法,我们可以将时间复杂度降到log(n)级别

2、快速幂

试想一个问题:求3^10, 试看如下分析

// 3^10 = 3 *3 * 3 * 3 * 3 * 3 * 3 * 3 * 3 * 3
// 3^10 = (3*3) * (3*3) * (3*3) * (3*3) * (3*3)
//      = (3*3)^5 
// 			= 9^5
// 由上面的分析我们可以看到,我们很轻易的就讲时间复杂度降了一半
// 那么对于 9^5呢?我们可以将奇数幂抽离一个数,变为 n * n^(偶数幂)
// 9^5 = (9^1) * (9^4)
// 		 = (9^1) * (81^2)
//     = (9^1) * (6561^1)
// 如此一来,我们就可以说任何数的任何幂都可以按这套算法来
// 我们先假定power都是大于0的自然数
// 返回的结果result = 1
// 对幂power进行操作,
// power一定要大于0
//  	如果power是偶数,我们就可以执行一次 /2 的操作(3^10 = 9^5),只需将底数平方一下
//    如果power是奇数, 我们将power - 1, 并将底数乘以到结果里面
//
public long pow(long base, long power) {
	long result = 0;
	while(power > 0) {
      	if(power % 2 == 0) {	// 偶数
          	base = base * base;
          	power = power >> 1;
        } else {							// 奇数
          	power = power - 1;
          	result = result * base;
        }
    }
  	return result;
}

如此一来,我们最后一定会转化几个幂为1的数相乘,时间复杂度则是 O(logn)

3、其他东西

在学习快速幂的时候,我了解到了一些其他以前忘记了的知识

在Java中,int类型的数据占据4个字节,32位,我们这里先用一个字节 byte来说

按照以前的理解,第一个位是符号位,剩下的7位代表数 ,byte的范围应该是这样的

// -(2^7 - 1) 到 (2^7 - 1) 也就是 -127 ~ 127
// [1][1][1][1][1][1][1][1] ~ [0][1][1][1][1][1][1][1]

但是翻看Java的Byte类我们可以看到

public static final byte MIN_VALUE = -128;
public static final byte MAX_VALUE = 127;

为什么负数表示的部分多了一个呢?

在此之前,我们可以先看看 0 在Byte中怎么表示

正数:[0][0][0][0][0][0][0][0]
负数:[1][0][0][0][0][0][0][0]

如上面的例子,0可以有两种表示的方法,分别是正数0和负数0,

我们很自然的就想到,将负数0代表负数所能表示的最大值

于是 [1][0][0][0][0][0][0][0]就表示 - 2^7 = -128 了

同样,这个方法也用在了int、long中

posted @ 2021-03-18 11:59  CRboyfriend  阅读(333)  评论(0)    收藏  举报