問題
n 段の
- 上る
順が 違えば、 別の 上り方として 数えます。 たとえば 「1 段、2 段」と 「2 段、1 段」は別です nは 1 以上 45 以下の整数です
入力と出力の例
例 1
「1、1、1、1」
入力
n = 4出力
5例 2
入力
n = 5出力
8例 3
1 段だけなら、
入力
n = 1出力
1面接での聞かれ方
面接では、
- 「階段を 1 段か 2
段ずつ 上ります。 n 段の 上り方は 何通りですか」 - 再帰で
書くと 「n が 45 だと、 どの くらい 時間が かかりますか?」と 続けて 聞かれます - 「1 回に 3 段まで
上れるとしたら?」と、 決まりを 変えて 聞かれる こともあります
数え方を
まず 考える手順
段 1
最後の 1 回に
段 2
素直な
段 3
一度求めた
段 4
再帰を
段 5
表を
ここから解答です。先に自分で書いてから読むと、考え方が残ります。
解答
Python
Python
def climb_ways(n):
prev, cur = 1, 1
for _ in range(n - 1):
nxt = prev + cur
prev = cur
cur = nxt
return curJavaScript
JavaScript
function climbWays(n) {
let prev = 1;
let cur = 1;
for (let i = 2; i <= n; i++) {
const next = prev + cur;
prev = cur;
cur = next;
}
return cur;
}始めの prev は
計算量
- 時間は O(n) です。
1 段から n 段まで、 1 回ずつ足し算をします - 使う
記憶は O(1) です。 持つのは 2 つの 変数だけです - 段 3 の
覚えておく 再帰と 段 4 の 表は、 時間は 同じ O(n) で、 記憶は O(n) です。 段 1 の 素直な 再帰は、 時間が n に 対して 指数的に増えます
よく ある間違い
- 素直な
再帰のまま出す。 小さな n では 正しく 速く 見えるので、 遅さに 気づきにくいです。 n が 30 を 超えた あたりから 目に 見えて 遅くなります - 始めの
値を 取り違える。 1 段を 1 通り、 2 段を 2 通りと したうえで、 ループの 回数を 1 回ずらすと 答えが 1 つ隣の 数に なります。 小さな n を 2、 3 個手で 確かめてから 回数を決めます - 大きな
数が あふれる 言語を 見落とす。 n が 45 の とき 答えは 約 18 億で、 32 ビットの 整数の 上限に 近いです。 Python と JavaScript では 問題ありませんが、 ほかの 言語で 書くなら 型の 大きさを 確かめます
面接での 話し方の例
書き始める
「最後の 1 回は 1 段か 2 段なので、
n 段の 上り方は n - 1 段と n - 2 段の 上り方を 足した数です。 そのまま 再帰で 書くと 同じ 計算を 繰り返して 遅いので、 小さい 段から 順に 答えを 積み上げます。 使うのは 前の 2 つだけなので、 変数 2 つで 足ります。 時間は O(n)、 記憶は O(1) です。」
書き終えたら、
「例 2 の n が 5 で
たどります。 0 段と 1 段を 1 通りずつとして 始め、 2 段は 2、 3 段は 3、 4 段は 5、 5 段は 3 と 5 を 足して 8 です。 例 1 の 4 段が 5 に なっている ことも、 途中で 確かめられます。」
