上楼梯问题&栈

上楼梯问题

背景

很多初学者可能都会遇到上楼梯问题,解决上楼梯问题的方法有很多,可能是递推,可能是动态规划。解决这些问题的方式无非就是调用函数,函数嵌套函数或者说用数组递推。
我很菜,我也很迟钝,刚开始遇到这样的问题,我立刻就投向了百度。这样的题解很多,但是我从来没记住。
你们遇到的版本可能是这样的:设有n 级台阶,每次只能上1-2级,问到最顶层一共有几种方法?
但是如果题目一改,设有n级台阶,每次只能上1-m级,问到最顶层一共有多少种方法,你还能轻而易于地在网上找到答案吗?我告诉你,我自己经历过,不好找。
是什么让只改变了一个字的题目变得更难了?究其原因,是因为不懂得这道题的核心。递推也好,动态规划也好,用函数解决,用数组递推,其实核心只有两点:

栈(数据结构)& 递推表达式

这样说可能有些费解,尤其对于初学者来说,接触这道题的时间可能还未触及数据结构的层次,或者有所耳闻,但是却没有没法有足够的模拟和抽象化的能力理解栈是怎样运行的,那么我们就从这道题开始,尽量让你用一道题就掌握栈这个数据结构

题目

有N级的台阶,你一开始在底部,每次可以向上迈最多K级台阶(最少1级),问到达第N级台阶有多少种不同方式。

分析

一开始遇到这道题,我们首先要模拟一下真实上楼梯的情景
k=2 : 1 2 3 5 8 13 21 34…
k=3 : 1 2 4 7 13 24 44 81…
k=4 : 1 2 4 8 15 29 56 108…
k=5 : 1 2 4 8 16 31 61 120…
我们用第一个例子:当你有1-2级步数的选择时,你在第一级台阶,只有一种选择,就是从地面迈一步走到第一级。你在第二级台阶时,其实有两种选择,一种选择是从第一级迈一步到第二级,或者是从地面迈两步到第二级。这时我们应该注意,从第一级卖到第二级,我们是没有考虑从地面到第一级一共有多少中方式的。虽然显而易见,只有一种。但如果我们是从第10级台阶到第11级台阶呢?我们依旧可以忽略是怎么从地面到第10级的,我们只需要知道从第10级只要一步就可以到第11级。那么到达第11级的方法之一就是先走到第10级,然后再迈一步。为什么说是方法之一呢?如果说你可以选择一次走两步呢?那么就可以从第9级一次迈两步到第11级。这时你可能会像,那么迈的这两步,是迈两次一步还是一次两步?多虑了,你要是迈了一步,你就到了第10级,再迈一步,那就是我说的第一种情况包含的方法数了。我们可以看出,只需要统计出从底层阶梯,在步数允许的范围内,一次迈到我们目标阶梯的情况就可以了。

抽象化

我们用F(n)表示到第几台阶的方法数,现在的假设是我们要上到第6个台阶,有1-3种步数可以选择。
那么开始模拟
F(0)=1 从地面出发,可以直接到1-3级台阶
F(1)=F(0)=1 存储到第1级台阶的方法数
F(2)=F(1)+F(0)=2
F(3)=F(2)+F(1)+F(0)=4
F(4)=F(3)+F(2)+F(1)=7
F(5)=F(4)+F(3)+F(2)=13
F(6)=F(5)+F(4)+F(3)=24

可视化

在这里插入图片描述
这实际上就是一个简单的栈的结构。什么意思呢?
你在第6级台阶,想知道一共有多少种方法,那你要知道F5 F4 F3的一共囊括了多少种方法。以此类推。
计算机是怎么处理的呢?
6->5->4->3->2->1
到底了,这是从地面到第5级台阶的传递链条,我们要一步步地将数据返回第5层,可是在返回的过程中,我们会遇到很多的分支,怎么办呢?我们必须要遍历这些分支,因为要获取底层的数据,才能得出上一层的数据,我知道了F1和F0,我才能知道F2。
其实这时候我们就会想,如果我多次遇到比如F3,我难道要再每次都找一遍F3的值是多少吗?F3找F2,F2找F1,F1找F0,才知道F3是多少。不需要,我们可以用数组存起来,调用的时候,就不用再麻烦了。其实这个过程在下方的代码是全程使用的,但是如果在函数方法中,这个方法有个高端的名字叫做记忆化搜索,其目的是剪枝。如果感兴趣的话,你可以自己学习一下,不过这些东西很快随着你的深入就逐渐接触了,理解栈这个概念并不需要(其实用函数来理解栈是最好的,但是也是最麻烦的,这里我就不在赘述(其实是我目前没能力讲清楚,也不想在一篇就把整个体系讲完))。

栈的定义是后进后出,你可以想象五个人进入了死胡同,1号先进,2号后进,最后是5号.大家意识到了,要出去的时候,谁先出?只能是5->4->3->2->1的顺序。这就是栈这个数据结构了。
这样做在计算机中有什么好处?我们要理解栈,不能靠上文这么一说,不知道怎么运行的,我们永远没法真正掌握栈的真谛。
计算机中,调用很重要。
假如一号程序进入了为程序建造的空间中,一号程序要知道某些东西,需要二号程序,就把二号程序拉近空间,然后类推,一直问到了五号,五号说他知道,告诉了四号,五号没用了,就可以出去了,四号知道了,告诉三号,他也出去了。一直到了一号,一号知道了,告诉了屏幕前的你,他也出去了。
这时最简单的线性调用,就是一个长条,我们要解决的是树状的调用
一号想知道一个问题,需要问二、三、四号,二号需要知道,需要问更多人。如果画出图来,很大一棵数,就像我上图一样(上图其实是有省略的,如果你仔细读了我的文章,我说过,我用了类似记忆化搜索的方式简化了这颗树)怎么办呢?如果在计算机中画一棵树,那别的无关数据怎么存储?插空吗?显然容易出错,为了计算机运行稳定,需要数据都是线性的存储。如何线性?还是栈,栈能保证数据时时刻刻都是线性的:
以下是一个栈的运行情况,用题目中给的情况,不考虑记忆化搜索。
6
6->5
6->5->4-
6->5->4->3-
6->5->4->3->2
6->5->4->3->2->1
6->5->4->3->2
6->5->4->3->2->0
6->5->4->3->2
6->5->4->3
6->5->4->3->1
6->5->4->3
6->5->4->3->0
6->5->4->3
6->5->4
6->5->4->2
6->5->4->2->1
6->5->4->2
6->5->4->2->0
6->5->4->2
6->5->4
6->5->4->1
6->5->4->1->0
6->5->4->1
6->5->4
6->5
6->5->3
6->5->3->2
6->5->3->2->1
6->5->3->2->1->0
6->5->3->2->1
6->5->3->1
6->5->3->1->0
6->5->3->1
6->5->3
6->5->2
6->5->2->1
6->5->2->1->0
6->5->2->1
6->5->2
6->5
6
6->4
6->4->3->2->1->0
6->4->3->2->1
6->4->3->2
6->4->3->2->0
6->4->3->2
6->4->3
6->4->3->1
6->4->3->1->0
6->4->3->1
6->4->3
6->4->3->0
6->4->3
6->4
………………………………
我实在是打不动了
最后到了
6
从哪开始就从哪结束
甚至你会发现这始终都是一条的栈这个结构,长度是对称的,前提是你把所有的链条都描绘出来。(你也可以写个程序)

题解

//上楼梯问题 
#include<stdio.h>
int main()
{
	int stairs,range_of_steps;//stairs 楼梯数  range_of_steps 可以选择的步数 
	scanf("%d %d",&stairs,&range_of_steps);
	int store[stairs+1]={0};//将在某一台阶向下走的方法数全部初始化为零 
	for(int i=1;i<=range_of_steps;i++)//当阶梯数小于等可于以选择的步数时 
	{
		for(int j=1;j<i;j++)
		{
			store[i]+=store[j];//例如当可以选择的步数大于等于5时 F(5)=F(4)+F(3)+F(2)+F(1) 
		}
		store[i]=store[i]+1;//F(5)=F(4)+F(3)+F(2)+F(1)+1 加上1,因为从第五级台阶可以一步走下去 
	}
	for(int i=range_of_steps+1;i<=stairs;i++)
	{
		for(int j=1;j<=range_of_steps;j++)
		{
			store[i]+=store[i-j];// F(6)=F(5)+F(4)+F(3)+F(2)+F(1) 此时从第六级台阶已经没办法直接下去了 
		}                        // 那么我们就只能从F(1)处,选择跨5步到F(6),从F(2)处,选择跨4步到F(6)以此类推 
	}
	printf("%d",store[stairs]);//我们到了最后一个阶梯,可以回顾一共有多少种方法上到最后一个台阶了 
}

谢谢阅读,文章若有错误亟待您的斧正。我想说的还有很多,但是我实在是码不动字了。

  • 3
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值