算法-动态规划-跳台阶

leetcode中有一个类型的题目是动态规划经常考察的点——斐波那契数列。跳台阶的问题是斐波那契数列的变种问题,总体思路上没有什么太大变化。

1.跳台阶easy

先来看这道题剑指 Offer 10- II. 青蛙跳台阶问题。题目描述如下:

一只青蛙一次可以跳上1级台阶,也可以跳上2级台阶。求该青蛙跳上一个 n 级的台阶总共有多少种跳法。
答案需要取模 1e9+7(1000000007),如计算初始结果为:1000000008,请返回 1。

示例 1:
输入:n = 2
输出:2

示例 2:
输入:n = 7
输出:21

示例 3:
输入:n = 0
输出:1
提示:0 <= n <= 100
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/qing-wa-tiao-tai-jie-wen-ti-lcof
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

根据题意可得:

  • 台阶数小于1,则跳的方案为0
  • 台阶数等于1,方案数为1
  • 台阶数等于2,方案数为2,可以跳一阶两次,或者可以跳二阶一次
  • 当台阶数大于2,方案数的递推公式为:
    d p [ i ] = d p [ i − 1 ] + d p [ i − 2 ] dp[i] = dp[i - 1] + dp[i - 2] dp[i]=dp[i1]+dp[i2]
    也就是说要想跳上当前台阶 i i i,需要从它的 i − 1 i - 1 i1或者 i − 2 i - 2 i2阶跳上来。
    那么核心代码为:
#include<iostreaam>
#include<vector>

using namespace std;

class Solution{
public:
	public:
    int numWays(int n) {
        if(n <= 1)
        {
            return 1;
        }
        int n_1 = 1;
        int n_2 = 1;
        int x = 1000000007;
        for(int i = 2;i <= n;i++)
        {
            n_1 = n_1 + n_2;
            n_2 = n_1 - n_2;
            n_1 = n_1 %x;
            n_2 =n_2 %x;
        }
        return n_1;
    }
};

注意方案数过大时需要取模。

2. 掷骰子middle

掷骰子游戏相比于跳台阶游戏其实并无太大差别,主要是方案数增多。原来跳台阶只能跳一阶或者两阶,方案数为最多为2。而掷骰子则方案数一下子增加到6。先来看题目:

骰子的点数有1-6点,掷骰子得到每个面的概率都是1/6,。现在我们要掷出某个点数 N ( 1 < = N < = 30 ) N(1 <= N <= 30) N1<=N<=30),可能的方案数有多少?注意:掷出点数1,2和2,1本质上是两种不同的方案
示例1:N = 3
输出:4
解释:可能的方案数为: ( 1 , 1 , 1 ) , ( 1 , 2 ) , ( 2 , 1 ) , ( 3 ) (1,1,1), (1, 2), (2, 1), (3) (1,1,1),(1,2),(2,1),(3),总的方案数有四种

根据题目信息可得,如果要想达到某个点数(台阶),可能的方案数从上一题的两种变成了现在的六种。

  • 如果是点数N小于等于6:

d p [ N ] = d p [ N − 1 ] + d p [ N − 2 ] + . . . + d p [ N − i ] , i < = N dp[N] = dp[N - 1] + dp[N - 2] + ...+dp[N - i],i <= N dp[N]=dp[N1]+dp[N2]+...+dp[Ni],i<=N

  • 如果点数N大于6

d p [ N ] = d p [ N − 1 ] + d p [ N − 2 ] + d p [ N − 3 ] + d p [ N − 4 ] + d p [ N − 5 ] + d p [ N − 6 ] dp[N] = dp[N-1] + dp[N- 2] + dp[N - 3] + dp[N - 4] + dp[N- 5] + dp[N- 6] dp[N]=dp[N1]+dp[N2]+dp[N3]+dp[N4]+dp[N5]+dp[N6]

如果点数小于等于6,那么就可以方案数就是已经存在的方案数之和。例如掷出点数3,那么可以从 d p [ 3 − 1 ] + d p [ 3 − 2 ] + d p [ 3 − 3 ] = d p [ 2 ] + d p [ 1 ] + d p [ 0 ] dp[3 - 1] + dp[3 - 2] + dp[3 - 3] = dp[2] + dp[1] + dp[0] dp[31]+dp[32]+dp[33]=dp[2]+dp[1]+dp[0]三者之和了。

如果指出点数大于6,那么方案数就是掷出点数的六种组合的结果。

上面这种考虑方式其实已经包含了掷出不同点数(顺序不同的)的组合了。

实际代码如下:

#include<iostream>
#include<vector>

using namespace std;

static int getNum(int N)
{
	if(N <= 1)
	{
		return 1;
	}
	vector<int>dp(N + 1, 0);
	dp[0] = 1;//点数为0的组合有一个
	dp[1] = 1;//点数为1的组合有一个
	for(int i = 2;i <= N;++i)
	{
		for(int j = 1;j <= 6 && i - j >= 0;++j)
		{
			dp[i] += dp[i - j];
		}
	}
	return dp[N};
}

int main()
{
	int N;
	cin >> N;
	cout << getNum(N) << endl;
	return 0; 
}
  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值