[编程题]:走台阶改进版(2021字节跳动)

[编程题]:走台阶

题目描述

小明回家要走一个阶梯,一共有n步。小明走阶梯有两个特点:

  • 每次只能走1步或者2步;
  • 不能连着两次走2步;

请计算他一共有多少种走法。

输入描述

楼梯的层数N,其中0 <= N < 100

输出描述

总共有多少种走法,以整数输出。

示例1

输入

2

输出

2

说明:2级台阶共有2种走法

示例2

输入

4

输出

4

说明:4级台阶共有4种走法

解题思路

很容易想到 斐波那契数列, 但是这里有一个“不能连着两次走2步”的限制条件。不能采用那种泰简单的动态规划思路。
如果用DFS搜索也可以,但是时间复杂度太高,肯定过不了的。

但是换一种思路,不要局限于常见的动态规划方法。
常见的动态规划是:设一个dp数组,再加上状态转移方程、边界条件就可以了。

本题中,“每次可以走1步或则2步,不能连着走2步”。因此,状态 i 不仅跟状态 i - 1 和状态 i - 2 有关,还跟到达状态 i - 1 和 状态 i - 2 的最后一步有关。如果到达状态 i - 2 的最后一步走了2步,那么就不能由状态 i - 2 转移到状态 i 了;如果最后一步走了1步,那么可以从状态 i - 2 转移到状态 i 。

因此。从分析可以看出:应该有两个状态转移。最后一步走了1步对应有一个状态转移;最后一步走了2步有另外一个状态转移。

状态转移

既然如此,为什么不可以设两个状态转移数组 dp[i][2].

dp[i][0]表示到达第 i 级台阶,并且最后一步走了 1 步的走法数;
dp[i][1]表示到达第 i 级台阶,并且最后一步走了 2 步的走法数。

有了这两个状态转移数组,就可以根部最后一步的不同情况进行不同的转移以满足题目中提出的要求。

状态转移方程

边界条件

dp[1][0] = 1 到达台阶 1 ,且最后一步走了1步的共有1种走法;
dp[1][1] = 0 到达台阶 1 ,且最后一步走了2步的共有0种走法;

dp[2][0] = 1 到达台阶 2 ,且最后一步走了1步的共有1种走法;
dp[2][1] = 1 到达台阶 2 ,且最后一步走了2步的共有1种走法;

状态转移方程

dp[i][0] = dp[i - 1][0] + dp[i - 1][1] (从i - 1级台阶到达 i 级台阶,走1步,到达i - 1级台阶的最后一步可1步也可2步)
dp[i][1] = dp[i - 2][0] (从i - 2级台阶到达 i 级台阶,走2步,因此到达i - 2级台阶的最后一步只能走1步)

代码

JAVA
import java.util.Scanner;

public class Main {
    private static int res = 0;

    public static void main(String[] args) {
        Scanner input = new Scanner(System.in);
        int n = input.nextInt();
        if (n <= 2) {
            System.out.println(n);
            return;
        }
        long[][] dp = new long[n + 1][2];
        dp[1][0] = 1;
        dp[1][1] = 0;

        dp[2][0] = 1;
        dp[2][1] = 1;
        for (int i = 3; i <= n; i++) {
            dp[i][0] = dp[i - 1][0] + dp[i - 1][1];
            dp[i][1] = dp[i - 2][0];
        }
        System.out.println(dp[n][0] + dp[n][1]);
    }
}

要注意一点,这里不能用int类型的数组。当N较大时,就越界了,这也是我oj没有完全通过的原因,考完了就想起来了。可以求得 1 ~ 100所有的情况如下:

1
2
3
4
6
9
13
19
28
41
60
88
129
189
277
406
595
872
1278
1873
2745
4023
5896
8641
12664
18560
27201
39865
58425
85626
125491
183916
269542
395033
578949
848491
1243524
1822473
2670964
3914488
5736961
8407925
12322413
18059374
26467299
38789712
56849086
83316385
122106097
178955183
262271568
384377665
563332848
825604416
1209982081
1773314929
-1696047951
-486065870
1287249059
-408798892
-894864762
392384297
-16414595
-911279357
-518895060
-535309655
-1446589012
-1965484072
1794173569
347584557
-1617899515
176274054
523858611
-1094040904
-917766850
-393908239
-1487949143
1889251303
1495343064
7393921
1896645224
-902979008
-895585087
1001060137
98081129
-797503958
203556179
301637308
-495866650
-292310471
9326837
-486539813
-778850284
-769523447
-1256063260
-2034913544
1490530305
234467045
-1800446499
-309916194

很明显越界了,该用long类型的数组,结果如下

1
2
3
4
6
9
13
19
28
41
60
88
129
189
277
406
595
872
1278
1873
2745
4023
5896
8641
12664
18560
27201
39865
58425
85626
125491
183916
269542
395033
578949
848491
1243524
1822473
2670964
3914488
5736961
8407925
12322413
18059374
26467299
38789712
56849086
83316385
122106097
178955183
262271568
384377665
563332848
825604416
1209982081
1773314929
2598919345
3808901426
5582216355
8181135700
11990037126
17572253481
25753389181
37743426307
55315679788
81069068969
118812495276
174128175064
255197244033
374009739309
548137914373
803335158406
1177344897715
1725482812088
2528817970494
3706162868209
5431645680297
7960463650791
11666626519000
17098272199297
25058735850088
36725362369088
53823634568385
78882370418473
115607732787561
169431367355946
248313737774419
363921470561980
533352837917926
781666575692345
1145588046254325
1678940884172251
2460607459864596
3606195506118921
5285136390291172
7745743850155768
11351939356274689
16637075746565861
24382819596721629
35734758952996318

可以看到这才没有越界。

C++
#include <iostream>
#include <vector>

using namespace std;

int main() {
    int n;
    cin >> n;
    if (n <= 2) {
        cout << n << endl;
        return 0;
    }
    vector<vector<long>> dp(n + 1, vector<long>(2, 0));
    dp[1][0] = 1;
    dp[1][1] = 0;

    dp[2][0] = 1;
    dp[2][1] = 1;

    for (int i = 3; i <= n; i++) {
        dp[i][0] = dp[i - 1][0] + dp[i - 1][1];
        dp[i][1] = dp[i - 2][0];
    }
    cout << dp[n][0] + dp[n][1] << endl;
    return 0;
}
Python
def helper(n):
    if n <= 2:
        print(n)
        return
    dp = [[0 for i in range(2)] for i in range(n + 1)]
    dp[1][0] = 1
    dp[1][1] = 0

    dp[2][0] = 1
    dp[2][1] = 1

    for i in range(3, n + 1):
        dp[i][0] = dp[i - 1][0] + dp[i - 1][1]
        dp[i][1] = dp[i - 2][0]
    print(dp[n][0] + dp[n][1])


if __name__ == "__main__":
    n = 100
    helper(n)

输出
在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/qq_27198345/article/details/108441758