Offer题9 斐波那契数列&青蛙跳台&矩形覆盖

  1. 斐波那契数列(面试题9)
  2. 青蛙跳台/变态青蛙跳台(变形1) 
  3. 矩形覆盖(变形2)

1.斐波那契数列(面试题9)
题目:写一个函数,输入n,求斐波那契(Fibonacci)数列的第n项。斐波那契数列的定义如下:
公式如下:

  • 有公式自然很简单,但是这道题的重点在于时间复杂度,递归的时间复杂度是O(2^n),循环的时间复杂度度是O(n),要用哪种写法显而易见
  • 下面给出的代码还有一种O(logn)的实现方式,但是对于这个类型的问题我觉得太复杂了,看看就行,其采用的方法如下:
  • 用后面这个公式递归计算
#include<iostream>
#include<time.h>
using namespace std;
long long Fibonacci_Recursive(unsigned int n)
{
    if(n<=0) return 0;
    if(n==1) return 1;
    return Fibonacci_Recursive(n-1)+Fibonacci_Recursive(n-2);
}
long long Fibonacci_Iterative(unsigned int n)
{
    if(n==0) return 0;
    if(n==1) return 1;
    long long FibN=0,FibSecond=1,FibFirst=0;
    for(unsigned i=2;i<=n;++i)
    {
        FibN = FibSecond + FibFirst;
        FibFirst = FibSecond;
        FibSecond = FibN;
    }
    return FibN;
}

struct Matrix2By2 //矩阵定义
{
	long long m_00;
	long long m_01;
	long long m_10;
	long long m_11;
	Matrix2By2(
		long long m00 = 0,
		long long m01 = 0,
		long long m10 = 0,
		long long m11 = 0
		):m_00(m00),m_01(m01),m_10(m10),m_11(m11){}
};
Matrix2By2 MatrixMultiply(const Matrix2By2 &matrix1,const Matrix2By2 &matrix2) //矩阵相乘
{
	return Matrix2By2(
		matrix1.m_00*matrix2.m_00 + matrix1.m_01*matrix2.m_10,
		matrix1.m_00*matrix2.m_01 + matrix1.m_01*matrix2.m_11,
		matrix1.m_10*matrix2.m_00 + matrix1.m_11*matrix2.m_10,
		matrix1.m_10*matrix2.m_01 + matrix1.m_11*matrix2.m_11
		);
}
Matrix2By2 MatrixPower(unsigned n) //矩阵的幂运算
{
	Matrix2By2 matrix;
	if(n==1)
		matrix = Matrix2By2(1,1,1,0);
	else if(n%2 == 0){
		matrix = MatrixPower(n/2);
		matrix = MatrixMultiply(matrix,matrix);
	}else if(n%2 == 1){
		matrix = MatrixPower((n-1)/2);
		matrix = MatrixMultiply(matrix,matrix);
		matrix = MatrixMultiply(matrix,Matrix2By2(1,1,1,0));
	}
	return matrix;
}
long long Fibonacci_MatrixRecursive(unsigned n)
{
    if(n==0) return 0;
    if(n==1) return 1;
	Matrix2By2 result = MatrixPower(n-1);
	return result.m_00;
}
int main()
{   
    clock_t start,step1,step2,step3;
    const unsigned num=10; 
    start = clock();
    //Test1
    cout<<num<<": "<<Fibonacci_Recursive(num)<<endl;
    step1 =clock();
    cout<<"cost "<<double(step1-start)/CLOCKS_PER_SEC<<" s"<<endl;
    //Test2
    cout<<num<<": "<<Fibonacci_Iterative(num)<<endl;
    step2 =clock();
    cout<<"cost "<<double(step2-step1)/CLOCKS_PER_SEC<<" s"<<endl;
	//Test3
	cout<<num<<": "<<Fibonacci_MatrixRecursive(num)<<endl;
    step3 =clock();
    cout<<"cost "<<double(step3-step2)/CLOCKS_PER_SEC<<" s"<<endl;
}
测试用例:
  • 功能测试(如输入3、5、10等)
  • 边界值测试(如输入0、1、2)
  • 性能测试(输入较大数字,如40、50、100)

斐波那契的变形题目如下:

2.青蛙跳台/变态青蛙跳台(变形1) 
题目:一只青蛙一次可以跳上1级台阶,也可以跳上2级台阶。求该青蛙跳上一个n级的台阶共有多少种跳法。
分析思路:
  1. 如果只有1级台阶:1种跳法;如果只有2级台阶:2种跳法;
  2. 如果有n级台阶:
    • 假设第一次跳1级,则跳法等于剩下(n-1)级的跳法
    • 假设第一次跳2级,则跳法等于剩下(n-2)级的跳法
    • 因此:f(n) = f(n-1)+f(n-2)   n>2时
  3. 显然这是个斐波那契问题
再变形题目:一只青蛙一次可以跳上1级台阶,也可以跳上2 级……它也可以跳上n 级,此时该青蛙跳上一个n级的台阶总共有多少种跳法?
分析思路: 
  1. 假设有n级台阶有f(n)种跳法,若n=1,f(1)=1
  2. 若n=2,f(2)=f(1)+1,这个1代表可以直接到达
  3. 若n=3,f(3)=f(2)+f(1)+1;
  4. 同理,错位相减法
    • 当n=n时,f(n)=f(n-1)+f(n-2)+……+f(2)+f(1)+1;
    • 当n=n-1时,f(n-1)=f(n-2)+f(n-3)+……+f(2)+f(1)+1;
    • 两式相减,f(n)-f(n-1)=f(n-1)  =>  f(n) = 2*f(n-1)=2²*f(n-2)=……=2^(n-1);
  5. 由以上数学归纳得,f(n)=2^(n-1);
3.矩形覆盖(变形2)
题目:用2×1的小矩形横着或者竖着去覆盖更大的矩形。请问用8个2×1的小矩形无重叠的覆盖一个2×8的大矩形,共有多少种方法

分析思路:
  1. 设覆盖2×8的方法为f(8)
    • 若第一个竖着放,则接下来要计算覆盖2×7的方法f(7)
    • 若第一个横着放,则其下方必定是横着放一个2×1,接下来要计算覆盖2×6的方法f(6)
    • 因此f(8) = f(7)+f(6)
  2. 根据以上分析,这是一个类似斐波那契数列的问题,需确定出f(1)=1,f(2)=2;
#include<iostream>
#include<math.h>
using namespace std;

long long FrogJump_Recursive(unsigned int n) //普通递归
{
    if(n<1) throw exception("input error");
    if(n==1) return 1;
    if(n==2) return 2;
    return FrogJump_Recursive(n-1)+FrogJump_Recursive(n-2);
}
long long FrogJump_Iterative(unsigned int n) //循环,青蛙跳台
{
    if(n<1) throw exception("input error");
    if(n==1) return 1;
    if(n==2) return 2;
    long long FrogN=0,FootStep1=1,FootStep2=2;
    for(unsigned i=3;i<=n;++i)
    {
        FrogN = FootStep2 + FootStep1;
        FootStep1 = FootStep2;
        FootStep2 = FrogN;
    }
    return FrogN;
}
long long  FrogJumpN_Iterative(unsigned n) //变态青蛙跳台
{
	if(n>0)
		return pow(2,n-1);
	else
		return -1;
}
long long SmallRectangleCoverBigRectangle(unsigned n) //n代表2×n
{
	if(n==1) return 1;
	if(n==2) return 2;
	long long MethodN=0,MethodTwo=2,MethodOne=1;
	for(int i=3;i<=n;++i)
	{
		MethodN = MethodTwo+MethodOne;
		MethodOne = MethodTwo;
		MethodTwo = MethodN;
	}
	return MethodN;
}
int main()
{   
    const unsigned num=8; 
    //Test1
    cout<<num<<"青蛙跳台: "<<FrogJump_Iterative(num)<<endl;
	//Test2
    cout<<num<<"变态青蛙跳台: "<<FrogJumpN_Iterative(num)<<endl;
	//Test3
	cout<<num<<"矩形覆盖:"<<SmallRectangleCoverBigRectangle(num)<<endl;
	return 0;
}














评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值