走台阶问题(递归方法+动态规划)

参考链接:https://time.geekbang.org/column/article/41440

基本的走台阶问题

问题描述:假设有n个台阶,每跨一步只能上1阶或者2阶台阶。求总共有多少种走法

思路1:假设n阶台阶有f(n)种走法,可以通过递归的方式进行求解。因为一步可以上1阶或者2阶台阶,那如果先上1个台阶则只需求出剩下的n-1个台阶的走法,如果先上2个台阶则只需求出剩下的n-2个台阶的走法,所以求n个台阶的走法变为求n-1和n-2个台阶的走法,则有f(n) = f(n - 1) + f(n - 2)(其中n > 2)。

 基于以上思路,代码实现如下:

/*
* @brief	利用递归解决该问题
*
* @method:    SolveStep
* @access:    public 
* @param:     size_t nStair
* @Return:    size_t
* @author:    RF_LYF
* @since:   2019/4/23  9:57 
*/
DWORD SolveStep(size_t nStair)
{
	if(nStair <= 0)
		return 0;
	else if(nStair < 3 && nStair > 0)
		return nStair;
	else
		return SolveStep(nStair - 1) + SolveStep(nStair -2);
}

该方法,当台阶的个数超过一定值得时候,求解速度很慢。

思路2:上面方法求解速度慢主要原因是存在好多重复计算。如下图所示:

由图可知在求解f(6)时f(3)被计算了3次,f(4)被被计算了2次,这种重复计算在上面的实现方式中出现很多,因此我们为了避免重复计算,可以将已经计算过的结果保存下来,从而减少计算次数,提高计算效率 。

基于以上分析,代码实现如下:

/**
* @brief    采用自顶向下的动态规划方式进行求解	
*
* @method:    SolveStepOpti
* @access:    public 
* @param:     size_t nStair
* @param:     int * Counter
* @Return:    ULONG
* @author:    RF_LYF
* @since:   2019/4/23  10:33 
*/
DWORD SolveStepOpti(size_t nStair, int *Counter)
{
	if(0 !=Counter[nStair])
		return Counter[nStair];
	if(nStair <= 0)
		return 0;
	else if(nStair > 0 && nStair < 3)
	{
		return Counter[nStair] = nStair;
	}
	else
	{
		Counter[nStair] = SolveStepOpti(nStair - 1, Counter) + SolveStepOpti(nStair - 2, Counter);
		return Counter[nStair];
	}
}

该方法的计算速度有了明显的提升。

思路3:利用循环的方式,完成该问题,采用自底向上的动态规划

/**
* @brief    利用循环求解问题,自底向上的动态规划求解问题
*
* @method:    SolveStepOpti2
* @access:    public 
* @param:     size_t nStair
* @Return:    DWORD
* @author:    RF_LYF
* @since:   2019/4/23  10:52 
*/
DWORD SolveStepOpti2(size_t nStair)
{
	if(nStair <= 0)
		return 0;
	else
	{
		DWORD step = 0;
		DWORD fstep = 1;
		DWORD ffstep = 0;
		for(size_t i = 1; i <= nStair; ++i)
		{
			step = fstep + ffstep;
			ffstep = fstep;
			fstep = step;
		}
		return step;
	}
}

该方法的计算速度也很快。

变形的走台阶问题

问题描述:还是n个台阶,同样每次可以跨1个台阶或者2个台阶。假定第一次迈的是左脚,求走完第n个台阶迈的正好是左脚(或者右脚)总共有多少走法

思路1:问题可以简化为,求n个台阶奇数次(或者偶数次)走完,共有多少种走法。假设将n个台阶奇数次走完共有 f奇(n)次,则

f奇(n) = f偶(n-1) + f偶(n-2),因为从n到n-1或者n-2已经走了一步。

基于以上分析,通过递归的方式实现,代码如下:

/**
* @brief	 递归法实现
*
* @method:    SolveStepOddEven
* @access:    public 
* @param:     int nStair
* @param:     size_t nStep(用来记录步数)
* @param:     DWORD& nCountOdd(用来记录奇数次走法的数目)
* @param:     DWORD& nCountEven(用来记录偶数次走法的数目)
* @Return:    void
* @author:    RF_LYF
* @since:   2019/4/23  11:28 
*/
void SolveStepOddEven(int nStair, size_t nStep, DWORD& nCountOdd, DWORD& nCountEven)
{
	
	if(nStair < 0)
		return;
	else if(nStair == 0)
	{
		if(nStep % 2 == 1)
			++nCountOdd;
		else
			++nCountEven;
		return;
	}
	else
	{
		++nStep;
		SolveStepOddEven(nStair - 1, nStep, nCountOdd, nCountEven);
		SolveStepOddEven(nStair - 2, nStep, nCountOdd, nCountEven);
	}
}

思路2:利用自底向上动态规划方式实现

/**
* @brief	动态规划 + 循环方法
*
* @method:    SolveStepOddOpti
* @access:    public 
* @param:     int nStair
* @param:     DWORD& nCountOdd(用来记录奇数次走法的数目)
* @param:     DWORD& nCountEven(用来记录偶数次走法的数目)
* @Return:    void
* @author:    RF_LYF
* @since:   2019/4/23  14:05 
*/
void SolveStepOddEvenOpti(int nStair, DWORD& nCountOdd, DWORD& nCountEven)
{
	if(nStair <= 0)
		return;
	else if(nStair == 1)
	{
		nCountOdd = 1;
		nCountEven = 1;
	}
	else
	{
		DWORD *pFOdd = new DWORD[nStair + 1];
		DWORD *pFEven = new DWORD[nStair + 1];
		pFOdd[0] = 0,pFOdd[1] = 1;
		pFEven[0] = 1,pFEven[1] = 0;
		for(int i = 2; i <= nStair; ++i)
		{
			pFOdd[i] = pFEven[i - 1] + pFEven[i - 2];
			pFEven[i] = pFOdd[i - 1] + pFOdd[i - 2];
		}
		nCountOdd = pFOdd[nStair];
		nCountEven = pFEven[nStair];
		delete []pFOdd;
		delete []pFEven;
	}
}

升级的台阶问题

问题描述:一个台阶总共有n级,如果每次可以跳1阶,2阶……n阶,求总共有多少种跳法

思路:

(1)n = 1时 f(1) = 1
(2)n = 2时分为2种方式,第1种跳1阶剩f(1)种跳法,第2种跳2阶只有1种跳法,因此 f(2) = f(2 - 1) + f(2 -2) = f(1) + 1          (3)当n=3时分为3种方式,先跳1阶剩f(2)种跳法,先跳2阶剩f(1)种跳法,先跳3阶只有1种跳法,因此 f(3) = f(2) + f(1) + 1         (4)当n个台阶时,则满足f(n) = f(n-1)+ f(n-2) + f(n-3) + ……+ f(1) + 1
(5)当n-1个台阶时,f(n-1) = f(n-2) + f(n-3) + ……+ 1
(6)f(n) - f(n-1) = f(n-1),则有f(n) = 2f(n-1),该公式则为递推公式

基于以上分析,代码实现如下:

long long SolveStepUpdate(int nStair)
{
	if(nStair <= 0)
		return 0;
	else if(nStair == 1)
		return 1;
	else
	{
		long long step = 0;
		long long fstep = 1;
		for(int i = 2; i <= nStair; ++i)
		{
			step = 2 * fstep;
			fstep = step;
		}
		return step;
	}
}

 

  • 20
    点赞
  • 61
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
好的,针对您的问题,我来讲一下动态规划爬楼梯问题5个台阶的分析方法。 在动态规划中,我们通常会使用一个数组来存储子问题的解,以便后续的子问题可以直接使用已解决的子问题的解,从而避免重复计算。对于爬楼梯问题,我们可以使用一个一维数组来存储到达每个台阶的不同路径数量。 以下是对于5个台阶的分析方法: 1. 递推法:根据题目可知,到达第n个台阶方法数为到达第n-1和第n-2个台阶方法数之和,因此可以使用递推的方式来求解。具体实现可以使用一个一维数组dp来存储到达每个台阶方法数,从dp[0]开始逐个计算,最终返回dp[n]即可。 2. 递归法:类似于递推法,也是通过递归的方式来求解。递归终止条件为到达第0个台阶和第1个台阶方法数分别为1和1,递归求解到达n-1和n-2个台阶方法数,最终返回它们之和即可。 3. 记忆化搜索法:在递归法的基础上,加入了记忆化的思想,即在求解每个子问题时,先查看该子问题是否已经计算过,如果已经计算过,则直接返回已有的解。如果没有计算过,则递归求解,并将结果存储到一个数组中,以便后续的子问题可以直接使用已解决的子问题的解。 4. 斐波那契数列法:利用斐波那契数列的递推公式,即f(n)=f(n-1)+f(n-2),来求解爬楼梯问题。具体实现可以使用两个变量f1和f2来存储f(n-1)和f(n-2)的值,然后依次更新它们的值,最终返回f(n)即可。 5. 矩阵快速幂法:在斐波那契数列法的基础上,利用矩阵快速幂的思想,可以将时间复杂度从O(n)降低到O(logn)。具体实现可以将斐波那契数列的递推公式转化为矩阵的形式,然后使用矩阵快速幂的方式来求解。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值