70. Climbing Stairs

練習日期:2026-01-15

難度:Easy

類型:Math、Dynamic Programming、Memoization

📘 題目敘述

你正在爬一個有 n 階的樓梯。每一次你可以選擇爬1 階2 階

請問總共有多少種不同的方法可以爬到樓梯頂端?

條件限制

  • 0 ≤ n ≤ 45

🧠 解題思路

我在思考這題時,並不是直接想「要怎麼算最快」,而是先問自己一個最根本的問題:

如果我要走到第 n 階,最後一步是怎麼來的?

這個問題一想清楚,整題的結構其實就已經出來了。

所有變數

  • n:樓梯的總階數(題目輸入)
  • step:用來記錄「走到第 i 階的方法數」的陣列
  • stair:目前正在計算的方法數所對應的階數
  • top:最後要回傳的結果,也就是走到第 n 階的方法數

🪜 主要流程步驟

關鍵觀察:最後一步的來源

假設我要走到第 n 階,那最後一步只可能有兩種情況:

  1. 從第 n-1 階走 1 步 上來
  2. 從第 n-2 階走 2 步 上來

除此之外,不存在第三種可能。

也就是說:

  • 所有「能走到第 n-1 階的方法」,最後再走 1 步,都可以到 n
  • 所有「能走到第 n-2 階的方法」,最後再走 2 步,也可以到 n

而這兩種來源 互不重疊,剛好涵蓋所有走法。


核心遞推關係

走到第 n 階的方法數 = 走到第 n-1 階的方法數 + 走到第 n-2 階的方法數

用符號表示就是:

step[n] = step[n-1] + step[n-2]


為什麼要先處理最小情況

在正式往上推之前,我會先確認最小的階數狀況:

n = 0

  • 沒有階梯要爬
  • 什麼都不做,也算是一種方法

n = 1

  • 只能走 1 階
  • 也只有一種方法

因此在我的邏輯中:

  • step[0] = 1
  • step[1] = 1

這兩個值就是整個推導的起點。

為什麼這是一題動態規劃(DP)

整理完整體想法後,我發現這題完全符合 DP 的特徵:

  • 大問題(走到第 n 階)可以拆成小問題(n-1n-2
  • 子問題的結果會被反覆使用
  • 有明確的狀態轉移關係

因此正確的做法不是暴力列出所有走法,而是:

  • 從小的階數開始
  • 把每一階的結果記錄下來
  • 一路推到第 n

和費波那契數列的關係

在寫完這題後,我也意識到:

  • 這個遞推關係
  • 這個初始條件

其實和 費波那契數列 是完全一樣的結構,只是題目換成了「爬樓梯」這個情境。

💻 程式碼實作

class Solution {
public:
    int climbStairs(int n) {
        vector<int> step = {1, 1};
        int stair = 2;
        int top;
        if (n == 0 || n == 1) {
            return 1;
        }
        while (stair <= n) {
            step.push_back(step[stair - 1] + step[stair - 2]);
            stair++;
        }
        top = step[n];
        return top;
    }
};

https://leetcode.com/problems/climbing-stairs/

作者: scottnick
撰寫日期: 2026-01-15
類別:
原文連結: https://scottnick.github.io/cpp-notes/all%20problems/70-climbing-stairs.html