牛客网在线编程专题《剑指offer-面试题9:题目二》跳台阶

版权声明:本文为博主原创文章,欢迎大家转载,但是要注明我的文章地址。 https://blog.csdn.net/program_developer/article/details/82632065

题目连接:

https://www.nowcoder.com/practice/8c82a5b80378478f9484d87d1c5f12a4?tpId=13&tqId=11161&tPage=1&rp=1&ru=/ta/coding-interviews&qru=/ta/coding-interviews/question-ranking

题目:

解题思路:

1. 问题分析

设f(n)表示青蛙跳上n级台阶的跳法数。
当只有一个台阶时,即n = 1时,只有1中跳法;
当n = 2时,有2种跳法;
当n = 3 时,有3种跳法;
当n很大时,青蛙在最后一步跳到第n级台阶时,有两种情况:
一种是青蛙在第n-1个台阶跳一个台阶,那么青蛙完成前面n-1个台阶,就有f(n-1)种跳法,这是一个子问题。
另一种是青蛙在第n-2个台阶跳两个台阶到第n个台阶,那么青蛙完成前面n-2个台阶,就有f(n-2)种情况,这又是另外一个子问题。

两个子问题构成了最终问题的解,所以当n>=3时,青蛙就有f(n)=f(n-1)+f(n-2)种跳法。
上面的分析过程,其实我们用到了动态规划的方法,找到了状态转移方程,用数学方程表达如下:

仔细一看,这不就是传说中的著名的斐波那契数列,但是与斐波那契数列的还是有一点区别,斐波那契数列从0开始,f(0)=0,f(1)=1,f(2)=1。斐波那契数列(Fibonacci Sequence),又称黄金分割数列,因为当n趋于无穷大时,前一个数与后一个数的比值无限接近于黄金比例。

2.解题方法

(1)递归实现

有了初始状态和状态转移方程,那么编程实现求解就不难了,递归算法实现如下:

package kuaishou;

public class qingwataijie {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		System.out.println(JumpFloor(5));
	}
	
	private static int JumpFloor(int target) {
		if(target == 1) {
			return 1;
		}else if(target == 2) {
			return 2;
		}else {
			return JumpFloor(target-1)+JumpFloor(target-2);
		}
	}

}

 但是我们都知道递归的时间复杂度和空间复杂度都很大,因此该递归算法的时间复杂度为O(2^{n}),空间复杂度为O(n)。

不明白时间复杂度和空间复杂度怎么算的,可以看一下这篇文章。

Reference:青蛙跳台阶问题暨斐波那契数列

(2)迭代实现

能用递归实现的算法,当然我们也能用迭代方法实现。

递归算法的一个缺点就是重复计算。我们可以把已经得到的数列中间项保存起来,如果下次需要计算的时候,我们先查找一下,如果前面已经计算过就不用再重复计算了。

迭代法:首先根据f(0)和f(1)计算出f(2),在根据f(1)和f(2)计算出f(3)......依次类推就可以算出第n项了。

package kuaishou;

public class qingwataijie {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		System.out.println(JumpFloor(5));
	}
	
	private static int JumpFloor(int target) {
		if(target == 1) {
			return 1;
		}else if (target == 2) {
			return 2;
		}else {
			int res = 0; 
			int a = 1;
			int b = 2;
			for(int i=3; i<=target; i++) {
				res = a + b;
				a = b;
				b = res;
			}
			return res;
		}
	}

}

 迭代法实现的时间复杂度为O(n),空间复杂度为O(1)。

这个算法是时间复杂度最低的算法吗?当然不是,最快的应该是下面的矩阵法。

(3)矩阵法

根据上面的地推公式,我们可以得到:

有了这个公式,我们只需要求得矩阵,即可得到f(n)。现在的问题转为如何求矩阵的乘方。如果只是简单地从0开始循环,n次方需要n次运算,那其时间复杂度仍然是O(n),并不比前面的方法快。

第一种解法矩阵拆分法,我们可以考虑乘方的如下性质:

$$ a^{n}=\left\{ \begin{aligned} a^{\frac{n}{2}}.a^{\frac{n}{2}} ,& \mbox{if }n \mbox{ is even} \\ a^{\frac{\left ( n-1\right )}{2}}.a^{\frac{\left ( n-1\right )}{2}}.a , & \mbox{if }n \mbox{ is odd}\\ \end{aligned} \right. $$

从上面的公式中我们可以看出,想求得n次方,就要先求n/2次方,再把n/2次方的结果平方一下即可。

第二种解法二进制法,我们可以类似地把a看做是二进制中的2,2^{7}=2^{3}\times 2^{3}\times 2^{1}也就是说可以把矩阵的幂转换成二进制来表示。从而可以将n次幂拆解成长度为logn的二进制数来表示:7=111(二进制)。这也是快速求多阶矩阵的核心方法。

这里暂时还没有写出可以参考的代码,不过有很多可以参考的博客。

【1】斐波那契数列(二)--矩阵优化算法

【2】算法之矩阵计算斐波那契数列

【3】青蛙跳台阶问题暨斐波那契数列

猜你喜欢

转载自blog.csdn.net/program_developer/article/details/82632065
今日推荐