斐波那契数列
以及青蛙跳台阶问题
package com.cloud.algorithm.demo;
import org.junit.Test;
/**
* DATE: 2021/3/31
* Author: xiaoqu
* Version: 1.0.0
* 斐波那契数列
*/
public class Topic10 {
/**
* 面试题10: 菲波那切数列
* 题目一:求斐波那契数列数列的第n项
* 写一个函数,输入n 求斐波那契(Fibonacci)数列的第n项。菲波那切数列的定义如下
* {0 n=0
* f(n)= {1 n=1
* {f(n-1)+f(n-2) n>1
*/
@Test
public void topic10_1() {
//递归
long i = System.currentTimeMillis();
long data = this.demo01(8);
long j = System.currentTimeMillis();
System.out.println("递归结果为:" + data + ",使用时间为:" + (j - i));
//循环
long i1 = System.currentTimeMillis();
long data1 = this.demo02(8);
long j1 = System.currentTimeMillis();
System.out.println("循环结果为:" + data1 + ",使用时间为:" + (j1 - i1));
/**
* 当n=50
* 递归结果为:12586269025,使用时间为:76074
* 循环结果为:12586269025,使用时间为:0
* 从结果可以看出递归慢很多,主要是递归里面很多计算都是重复的
*/
}
/**
* 题目二:青蛙跳台阶问题
* 一只青蛙一次可以调一级台阶,也可以跳2级台阶,
* 求该青蛙跳上一个n级的台阶总共有多少种跳法
*/
@Test
public void topic10_2() {
/**
* 如果n=1 结果为1
* 如果n=2 结果为2
* 如果为n (n>2) 第一步有两种,要么第一步跳一下,要么跳两下,
* 如果第一步跳一下,则剩下的台阶为 n-1
* 如果第一步跳两下,则剩下的台阶为n-2
* 依次类推 f(n)=f(n-1)+f(n-2)
*/
//递归
long i = System.currentTimeMillis();
long data = this.demo03(40);
long j = System.currentTimeMillis();
System.out.println("递归结果为:" + data + ",使用时间为:" + (j - i));
//循环
long i1 = System.currentTimeMillis();
long data1 = this.demo04(40);
long j1 = System.currentTimeMillis();
System.out.println("循环结果为:" + data1 + ",使用时间为:" + (j1 - i1));
/**
* 递归结果为:165580141,使用时间为:421
* 循环结果为:165580141,使用时间为:0
*/
}
/**
* 题目3:青蛙跳台阶变形版
* 青蛙一次可以跳上1级台阶,也可以跳2级,。。。。也可以跳n级
* 此时跳上一个n级台阶总共有多少跳法
*/
@Test
public void topic10_3() {
/**
* 青蛙如果第一步跳一级台阶 剩下的台阶跳法就是f(n-1)
* 青蛙如果第一步跳二级台阶 剩下的台阶跳法就是f(n-2)
* 。。。。。
* 青蛙如果第一步跳n-1级台阶 剩下的台阶跳法就是f(1)
* 青蛙如果第一步跳n级台阶 剩下的台阶跳法就是f(0)
* 即总跳法为 f(n)=f(n-1)+f(n-2)+......+f(1)+f(0)
* 变形为
* f(n-1)=f(n-2)+f(n-3)+......+f(1)+f(0)
* 两者相减得如下
* f(n)-f(n-1)=f(n-1)
* f(n)=2f(n-1)
* 2f(n-1)=2x2f(n-2)
* f(n)=2x2f(n-2)
* 推论得出
* f(n)=2^(n-1) f(n)=2^(n-1)
* 即实际求的是
*
* f(n)=2^(n-1)
*/
long l = this.demo05(3);
System.out.println(l);
}
/**
* 口 口口口口口口口口
* 口 口口口口口口口口
* <p>
* 我们可以用2X1的小矩形横着或者竖着去覆盖更大的矩形,
* 请问用8个2X1的小矩形无重叠地覆盖在一个2X8的大矩形
* 总共有多少种方法
*/
@Test
public void topic10_4() {
/**
* 如果第一个横着放 则右边剩余6个 为 f(6)
* 如果第一个竖着放 则右边剩余7个 为 f(7)
* 则总次数为 f(8)=f(6)+f(7) 解法依旧为斐波那契数列
*/
}
/**
* 递归
*
* @return
*/
public long demo01(long n) {
if (n == 0) {
return 0;
} else if (n == 1) {
return 1;
} else {
return demo01(n - 1) + demo01(n - 2);
}
}
/**
* 时间复杂度为O(n)
*
* @param n
* @return
*/
public long demo02(long n) {
if (n == 0) {
return 0;
} else if (n == 1) {
return 1;
} else {
long k1 = 0;
long k2 = 1;
long kn = 0;
for (int i = 2; i <= n; i++) {
kn = k1 + k2;
k1 = k2;
k2 = kn;
}
return kn;
}
}
/**
* 递归
*
* @param n
* @return
*/
public long demo03(long n) {
if (n == 1) {
return 1;
} else if (n == 2) {
return 2;
} else {
return demo03(n - 1) + demo03(n - 2);
}
}
/**
* 循环
*
* @return
*/
public long demo04(long n) {
if (n == 1) {
return 1;
} else if (n == 2) {
return 2;
} else {
long kn = 0;
long kn1 = 1;
long kn2 = 2;
for (int i = 3; i <= n; i++) {
kn = kn1 + kn2;
kn1 = kn2;
kn2 = kn;
}
return kn;
}
}
/**
* 2^(n-1)
*
* @return
*/
public long demo05(long n) {
int j = 1;
for (int i = 1; i < n; i++) {
j = 2 * j;
}
return j;
}
}