玩玩快速冥(LeetCode50题与70题以及联系斐波那契)

一.算法快速幂

今天刷到两个题,比较有意思,还是记录一下.

先来讲讲50题.

LeetCode50(Pow(x,n))

实现 pow(x, n) ,即计算 x 的整数 n 次幂函数(即,xn )。

这道题一看很平常啊,不就一直乘嘛,循环走一次就够了.但是很抱歉,单纯的想法终究迎来了超时.而且还是个中等的题目,意识到没那么简单.我们需要换种思路.

对于2的128次方,如果我们需要一次次循环遍历,得需要128次才能计算得出.

而我们仔细把128拆分可以发现

2 * 2 = 2²

2² * 2² = 2⁴

2⁴ * 2⁴ = 2^8

2^8 * 2^8 = 2^16

2^16 * 2^16 = 2^32

2^32 * 2^32 = 2^64

2^64 * 2^64 = 2^128

我们只需要7次就能得到答案.
那有人就问了,你这是2的次数幂可以这样算而已.那我们对于不是2的整数幂如何处理呢?

例如7的105次方,我们可以将它进行拆分

这样不好看105,我们转化成2进制试试.

0110 1001

即等于 7^64+ 7^32 + 7^8 + 7^1 = 7^105.

是不是我们每次都能拆分成2的整数幂

对于7*64我们可不可以通过之前的快速幂得到,答案是肯定的,

那我们怎么去判定什么时候需要去进行这个拆分的相乘呢?在上图中我们注意到,我们需要的快速幂的数都是正好二进制置为1的数.我们只需要去进行取余,只要末尾数为1时,此时我们需要将快速幂的结果相乘,其余步骤只做乘数的累加即可.每进行一次将次方数除二.

我们写出伪代码

复制代码
function quickPow(a,n)
	r = 1
	while n != 0
		if n mod 2 == 1
			r = r * a
		a=a*a
		n = n/2
	return r

即可以通过这张图这样理解

那我们还可以进一步优化这段代码.取余的运算我们可以对1做&运算.

而对于除以2我们可以右移一位来实现.

而对于这道题,我们还需要注意一点,就是有负数次幂的时候.其实本质上是一样的,因为负数次幂实际上就等于 1 / a^n.所以最终代码为

java 复制代码
class Solution {
    public double myPow(double x, long n) {
        return n >= 0? quickPow(x,n): 1 / quickPow(x,-n);
    }
    public double quickPow(double x,long n){
        double r = 1.0;
        while(n != 0){
            if((n % 2) == 1){
                r = r * x; 
            }
            x = x * x;
            n = n >> 1;
        }
        return r;
    }
}

LeetCode70(爬楼梯)

假设你正在爬楼梯。需要 n 阶你才能到达楼顶。

每次你可以爬 1 或 2 个台阶。你有多少种不同的方法可以爬到楼顶呢?

这道题其实我们有几种解法,我介绍两种解法.

第一种,来复习一下动态规划.根据题目我们可以列式子

F(n) = F(n-1) + F(n-2);

即对于任意一个台阶都等于前一个台阶的次数加上前两个台阶的次数.

对于0阶台阶,我们只有一种方法到达,而对于1阶台阶我们也是只有一种方法到达.对于F(2),即2阶台阶,我们有两种方式到达,走两步或者一次性走两步.根据公式也能推导F(2) = F(1) + F(0).依次类推F(3) = F(2) + F(1) = 3次

F(4) = F(3) + F(2) = 5次...

所以每一阶都是前两阶之和.代码为

java 复制代码
class Solution {
    public int climbStairs(int n) {
        int f1 = 0,f2 = 0,step = 1;
        for(int i = 0;i < n;i++){
            f1 = f2;
            f2 = step;
            step = f1 + f2;
        }
        return step;
    }
}

那我们如何利用之前提到过的快速幂解决这个问题呢.我们可以利用矩阵.

我们仔细来看看这个表达式

而对于[{f(n),f(n-1)}]的矩阵我们依旧可以像这样展开,所以最终能得到

这不就是个幂等式吗,所以依照之前的模板.代码为

java 复制代码
public class Solution {
    public int climbStairs(int n) {
        int[][] q = {{1, 1}, {1, 0}}; //定义之前分析到的结果的矩阵
        int[][] res = pow(q, n);
        return res[0][0];
    }

    public int[][] quickPow(int[][] q, int n) {
        int[][] result = {{1, 0}, {0, 1}}; //单元矩阵
        while (n > 0) {
            if ((n & 1) == 1) {
                result = mul(result , q);
            }
            q = mul(q, q);
            n >>= 1;
        }
        return result ;
    }

    public int[][] mul(int[][] x, int[][] y) {
        int[][] res = new int[2][2];
        for (int i = 0; i < 2; i++) {
            for (int j = 0; j < 2; j++) {
                res [i][j] = x[i][0] * y[0][j] + x[i][1] * y[1][j];
            }
        }
        return res ;
    }
}

注意: 大家有没有发现一个点啊,这玩意的公式有点像那个.斐波那契是叭 .

都是F(n) = F(n-1) + F(n-2)

那对于求斐波那契的多少项我们是不是同样能够这样处理.所以我们求斐波那契的代码和这个是一致的.

相关推荐
极小狐1 小时前
如何使用极狐GitLab 软件包仓库功能托管 maven?
java·运维·数据库·安全·c#·gitlab·maven
容辞1 小时前
算法-贪婪算法
算法·贪心算法
.生产的驴1 小时前
SpringBoot 集成滑块验证码AJ-Captcha行为验证码 Redis分布式 接口限流 防爬虫
java·spring boot·redis·分布式·后端·爬虫·tomcat
Evand J1 小时前
MATLAB程序演示与编程思路,相对导航,四个小车的形式,使用集中式扩展卡尔曼滤波(fullyCN-EKF)
人工智能·算法
野犬寒鸦3 小时前
MySQL索引使用规则详解:从设计到优化的完整指南
java·数据库·后端·sql·mysql
思考的橙子3 小时前
Springboot之会话技术
java·spring boot·后端
椰萝Yerosius3 小时前
[题解]2023CCPC黑龙江省赛 - Ethernet
算法·深度优先
钰爱&3 小时前
【Linux】POSIX 线程信号量与互斥锁▲
java·开发语言·jvm
IT猿手4 小时前
基于 Q-learning 的城市场景无人机三维路径规划算法研究,可以自定义地图,提供完整MATLAB代码
深度学习·算法·matlab·无人机·强化学习·qlearning·无人机路径规划
黑匣子~5 小时前
java集成telegram机器人
java·python·机器人·telegram