C语言/数据结构动态规划题解:爬楼梯(含坏台阶)——避开障碍物的路径计数

问题描述

小明正在爬一个有 n 级台阶的楼梯,但是他的体力有限,每次只能爬 1 级或者 2 级台阶。更特别的是,楼梯的某些台阶是坏的,小明不能踩上去。小明的目标是爬到楼梯的顶部(第 n 级台阶),但必须避开所有坏掉的台阶。现在,请你帮助小明计算,在避开所有坏台阶的情况下,他有多少种不同的方式可以爬到楼梯顶部。

注意:

  • 楼梯台阶编号从 0 开始(0 表示地面起点)到 n 结束(n 表示顶部终点)
  • 共有 n+1 个位置(0, 1, 2, ..., n),但只有 n 级实际台阶(从 1 到 n)
  • 坏台阶列表 bad 中的元素表示不能踩的台阶编号(在 1 到 n-1 范围内)

要求:

  1. 设计一个算法,计算小明爬到顶部的不同方式数量。
  2. 算法需要高效处理较大的 n 值,时间复杂度应为 O(n)。

测试样例

样例1:

输入:n = 3, bad = [2] 输出:1 解释:台阶编号为 0(起点)、1、2、3(终点)。第 2 级台阶是坏的。 有效路径:

  • 0 → 1 → 3(先爬1级到1,再爬2级到3) 无效路径:
  • 0 → 2 → 3(第2级是坏的)
  • 0 → 1 → 2 → 3(经过坏台阶2) 所以只有 1 种方式。

样例2:

输入:n = 4, bad = [1, 3] 输出:1 解释:台阶编号为 0、1、2、3、4。第 1 级和第 3 级是坏的。 有效路径:

  • 0 → 2 → 4(先爬2级到2,再爬2级到4) 无效路径:
  • 0 → 1 → ...(第1级坏)
  • 0 → 2 → 3 → 4(第3级坏) 所以只有 1 种方式。

样例3:

输入:n = 5, bad = [] 输出:8 解释:没有坏台阶,这就是经典的爬楼梯问题。爬到第 5 级的方式数量是 8(斐波那契数列:1,2,3,5,8)。 有效路径包括所有可能的 1 步和 2 步组合。

样例4:

输入:n = 2, bad = [] 输出:2 解释:台阶编号为 0、1、2。没有坏台阶。 有效路径:

  • 0 → 1 → 2(两次1步)
  • 0 → 2(一次2步) 所以有 2 种方式。

样例5:

输入:n = 3, bad = [] 输出:3 解释:台阶编号为 0、1、2、3。没有坏台阶。 有效路径:

  • 0 → 1 → 2 → 3
  • 0 → 1 → 3
  • 0 → 2 → 3 所以有 3 种方式。

约束条件

  • 1 ≤ n ≤ 1000
  • 0 ≤ len(bad) ≤ n
  • bad 中的元素互不相同,且都在 1, n-1 范围内(坏台阶不会包括第 0 级或第 n 级)
  • 答案保证在 32 位有符号整数范围内

解题提示

可以使用动态规划:

  • 设 dpi 表示到达第 i 级台阶的方式数
  • 初始化:dp0 = 1(起点)
  • 对于每个位置 i(从 1 到 n):
    • 如果 i 是坏台阶,则 dpi = 0
    • 否则,dpi = dpi-1 + dpi-2(可以从 i-1 爬 1 步或从 i-2 爬 2 步到达)
  • 注意处理边界条件(i-1 和 i-2 需要大于等于 0)

程序代码

#include <stdio.h>

#include <stdlib.h>

#include <string.h>

int climbStairs(int n, int* bad, int badSize) {

// 标记坏台阶

int* isBad = (int*)calloc(n + 1, sizeof(int));

for (int i = 0; i < badSize; i++) {

isBadbad\[i] = 1;

}

// dpi 表示到达第 i 级台阶的方式数

int* dp = (int*)malloc((n + 1) * sizeof(int));

dp0 = 1;

for (int i = 1; i <= n; i++) {

if (isBadi) {

dpi = 0;

} else {

dpi = 0;

if (i - 1 >= 0) dpi += dpi - 1;

if (i - 2 >= 0) dpi += dpi - 2;

}

}

int result = dpn;

free(dp);

free(isBad);

return result;

}

int main() {

int bad1\[\] = {2};

printf("%d\n", climbStairs(3, bad1, 1)); // 1

int bad2\[\] = {1, 3};

printf("%d\n", climbStairs(4, bad2, 2)); // 1

int bad3\[\] = {};

printf("%d\n", climbStairs(5, bad3, 0)); // 8

printf("%d\n", climbStairs(2, bad3, 0)); // 2

printf("%d\n", climbStairs(3, bad3, 0)); // 3

return 0;

}

cpp 复制代码
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int climbStairs(int n, int* bad, int badSize) {
    // 标记坏台阶
    int* isBad = (int*)calloc(n + 1, sizeof(int));
    for (int i = 0; i < badSize; i++) {
        isBad[bad[i]] = 1;
    }
    
    // dp[i] 表示到达第 i 级台阶的方式数
    int* dp = (int*)malloc((n + 1) * sizeof(int));
    dp[0] = 1;
    
    for (int i = 1; i <= n; i++) {
        if (isBad[i]) {
            dp[i] = 0;
        } else {
            dp[i] = 0;
            if (i - 1 >= 0) dp[i] += dp[i - 1];
            if (i - 2 >= 0) dp[i] += dp[i - 2];
        }
    }
    
    int result = dp[n];
    free(dp);
    free(isBad);
    return result;
}

int main() {
    int bad1[] = {2};
    printf("%d\n", climbStairs(3, bad1, 1));  // 1
    
    int bad2[] = {1, 3};
    printf("%d\n", climbStairs(4, bad2, 2));  // 1
    
    int bad3[] = {};
    printf("%d\n", climbStairs(5, bad3, 0));  // 8
    printf("%d\n", climbStairs(2, bad3, 0));  // 2
    printf("%d\n", climbStairs(3, bad3, 0));  // 3
    
    return 0;
}

运行结果

相关推荐
山下梅子酒2251 小时前
洛谷-入门-B2081
c语言
wuminyu2 小时前
Virtual Thread重投递至ForkJoinPool任务队列过程解析
java·linux·c语言·jvm·c++
All for pursuit.2 小时前
【回溯-6】79.单词搜索
数据结构·c++·算法·leetcode
Navigator_Z2 小时前
LeetCode //C - 1281. Subtract the Product and Sum of Digits of an Integer
c语言·算法·leetcode
iCxhust2 小时前
51单片机电力载波应用开发(七)广播通讯
c语言·开发语言·单片机·嵌入式硬件·51单片机
Benny_Tang3 小时前
AT_arc180_d [ARC180D] Division into 3 题解
数据结构·c++·算法
殷色玫瑰3 小时前
C++ STL:stack、queue、priority_queue 与容器适配器详解
java·开发语言·数据结构·c++·算法·visualstudio
Hi202402173 小时前
同一个 NMS 算子,两种语言实现:CUDA C 与 Rust 生成 LLVM IR 和 Vortex 汇编的差异
c语言·汇编·rust·gpgpu·vortex·cudac
lhbweilai4 小时前
深挖FreeRTOS内核实现(二)
c语言·汇编·stm32·单片机