博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
刷题 爬楼梯 递归 回溯 动态规划
阅读量:3923 次
发布时间:2019-05-23

本文共 2302 字,大约阅读时间需要 7 分钟。

微信搜索:编程笔记本,获取更多干货知识

微信搜索:编程笔记本,获取更多干货知识
微信搜索:编程笔记本,获取更多干货知识

点击上方蓝字关注我,我们一起学编程

欢迎小伙伴们分享、转载、私信、赞赏

今天分享一道字节跳动的面试题:爬楼梯Ⅱ

题目描述:

一个台阶总共有 n 级,如果一次可以跳 1 级,也可以跳 2 级,但不能连续两次跳 2。求总共有多少总跳法。

分析:

如果没有“不能连续两次跳 2 级”的约束,那么我们很容易写出下面的递归函数:

int climb(int n){
if (n == 1 || n == 2) {
return n; } return climb(n - 1) + climb(n - 2);}

上面的代码中,势必包括了连续两次跳 2 级的跳法。那么,我们尝试着去除这些多余的跳法。

若要去除这些跳法,我们就要去除连续两次三次四次 …… 跳 2 级的跳法,这样一来,势必会将问题变得极其复杂。

我们换一种思路:不能连续两次跳 2的意思,换句话说就是跳完 2 级后只能再跳 1。那么,我们将“跳完 2 级后再跳 1 级”封装成一个整体—— 3

这样一来,题目就等价于:一个台阶总共有 n 级,如果一次可以跳 1 级,也可以跳 3 级,。求总共有多少总跳法。

我们很容易写出下面这段代码:

微信搜索:编程笔记本,获取更多干货知识

微信搜索:编程笔记本,获取更多干货知识
微信搜索:编程笔记本,获取更多干货知识

int climb(int n){
if (n == 1 || n == 2 || n == 3) {
return n; } return climb(n - 1) + climb(n - 3);}

分析到这里,题目就已经求解完成了。为了避免部分小伙伴对这种解法正确性的怀疑,我们用最笨的回溯法来验证一下。

#include 
using namespace std;int climb(int n){
if (n == 1 || n == 2 || n == 3) {
return n; } return climb(n - 1) + climb(n - 3);}// 回溯法int climb_test(int now, int all, bool jmp2){
int cnt = 0; if (now == all) {
// 抵达终点,数量加一 ++cnt; return cnt; } if (now > all) {
// 跳多了,直接返回 return cnt; } // 未到终点 cnt += climb_test(now + 1, all, false); // 跳 1 级,并将“跳 2 级”标识复位 if (!jmp2) {
cnt += climb_test(now + 2, all, true); // 跳 2 级,并将“跳 2 级”标识置位 } return cnt;}int main(){
string info = "correct"; for (int i = 1; i < 50; ++i) {
int num1 = climb(i); int num2 = climb_test(0, i, false); if (num1 != num2) {
info = "error"; break; } } cout << info << endl; return 0;}

编译运行:

微信搜索:编程笔记本,获取更多干货知识

微信搜索:编程笔记本,获取更多干货知识
微信搜索:编程笔记本,获取更多干货知识

jincheng@#:$ g++ test.cpp -o testjincheng@#:$ ./testcorrect

可见,我们写的代码是正确的。

其实,递归法是十分消耗资源的一种算法,主要是函数堆栈的动态生成与切换。下面我们使用动态规划法改写递归法的代码。

动态规划其实就是用空间换时间的方法,我们将子问题的解保存下来,这样一来,重复的子问题就只需计算一次,从而优化了算法的时间复杂度。

int climb_dp(int n){
vector
dp(n+1); // 保存子问题的解,dp[i] 表示 i 级楼梯的总跳法 dp[1] = 1; // 初始化 dp[2] = 2; dp[3] = 3; for (int i = 4; i <= n; ++i) {
dp[i] = dp[i - 1] + dp[i - 3]; } return dp[n];}

好啦,今天的内容就到这里!有不明白的小伙伴欢迎私信咨询,我一定知无不言!

微信搜索:编程笔记本,获取更多干货知识

微信搜索:编程笔记本,获取更多干货知识
微信搜索:编程笔记本,获取更多干货知识

你可能感兴趣的文章
hdu 3586 Information Disturbing(树形DP+二分查找+删变暖)
查看>>
hdu 4003 Find Metal Mineral(树形DP+分组背包,每个物品必须只能选一次)
查看>>
hdu 4276 The Ghost Blows Light(树形DP+最短路+分组背包)好题。。。
查看>>
zoj 3537 Cake(区间DP+最优三角形剖分)待续
查看>>
poj 2955 Brackets(区间DP,经典问题)求有规律的括号的最大长度
查看>>
poj 1651 Multiplication Puzzle(区间DP,直接用矩阵相乘的方式也对)
查看>>
zoj 3469 Food Delivery(区间DP,好题,)
查看>>
poj 3280 Cheapest Palindrome(区间DP)
查看>>
poj 1141 Brackets Sequence(区间DP,求最小,输出路径,较难)
查看>>
poj 3661 Running(dp,设计状态,)
查看>>
uva 1351 - String Compression(区间DP,好题,较难)
查看>>
判断一个串是否是由重复子串组成
查看>>
No Girlfriend(简单题)
查看>>
[F] Teacher's Problem(处理大数时,优化很重要)
查看>>
[J] Dumb Typo(题目很简单,比赛错在不该自己计算,应该用电脑跑一遍的)
查看>>
[1545] New Year 2014(数位DP,现放标程,待看)
查看>>
CF 149D Coloring Brackets(区间DP,好题,给配对的括号上色,求上色方案数,限制条件多,dp四维)
查看>>
Light OJ 1422 - Halloween Costumes (区间DP)
查看>>
poj 2559 Largest Rectangle in a Histogram(DP二维超内存,用一维或者用结构体)
查看>>
Ningbo [1217] Dinner(简单题,但是注意输出,pe3遍)
查看>>