コンピューターサイエンス:アルゴリズム / OS / ネットワーク / DBの導入スライド
コンピューターサイエンス:アルゴリズム / OS / ネットワーク / DB - 階乗(再帰)
積んでから、帰り道で掛ける
実行を進めて、factorial(4) の箱が底まで積まれてから値が降りてくるところを見てください。
基底を n <= 1 と書くのは 0 のためだけではありません。うっかり負の数が来ても底に着かせるための保険です。
1 / 1
コンピューターサイエンス:アルゴリズム / OS / ネットワーク / DB - フィボナッチ数(再帰)
同じ fib を何度も呼んでいる
n を 1 ずつ上げて、fib(k) ごとの呼び出し回数がどこから急に伸びるか見てください。
基底で return 1 と書くと fib(0) が 1 になり、数列全体が 1 つずれます。ここだけは return n です。
1 / 1
コンピューターサイエンス:アルゴリズム / OS / ネットワーク / DB - 累乗(再帰)
1 ずつ減らすか、半分に割るか
exp を動かして、上下 2 列のマスの数がどこから離れていくか見てください。
引数が 2 つに増えても、減らすのは exp だけで base は据え置きです。動かす引数を 1 つに決めるのが引数が増えたときのコツです。
1 / 1
コンピューターサイエンス:アルゴリズム / OS / ネットワーク / DB - 配列の合計(再帰)
先頭 1 個と残りに切る
配列の長さを変えて、切るたびに作られる残りの配列が何マスぶん増えるか見てください。
この切り方は合計のためだけの小技ではありません。マージソートも木の走査も、同じ「先頭と残り」の形で書かれています。
1 / 1
コンピューターサイエンス:アルゴリズム / OS / ネットワーク / DB - 桁数を数える(再帰)
1 の位を落としながら数える
割る回数を進めて、落ちた桁が下のトレイにどう溜まるか見てください。
JavaScript では n / 10 が小数になります。Math.floor を挟まないと桁が落ちきらず、いつまでも 1 桁になりません。
1 / 1
コンピューターサイエンス:アルゴリズム / OS / ネットワーク / DB - 文字列を逆順(再帰)
同じ順で取り出して、後ろに足す
取り出した文字数を進めながら、足す場所を入れ替えて結果の変わり方を見てください。
末尾から取り出す書き方でも同じ答えになります。自分がどちら側から組み立てているかを言葉にできれば、その再帰はもう自分のものです。
1 / 1
コンピューターサイエンス:アルゴリズム / OS / ネットワーク / DB - ユークリッドの互除法(GCD)
余りを取ると一気に小さくなる
a を大きく動かして、帯が 0 に着くまでの段数がほとんど増えないことを見てください。
a より b が大きい状態で呼んでも壊れません。1 手目の a % b が a のまま返り、次の手で勝手に入れ替わります。
1 / 1
コンピューターサイエンス:アルゴリズム / OS / ネットワーク / DB - 線形探索で位置を返す
戻り値の -1 をどう受け取るか
探す値と判定の書き方を切り替えて、どの組み合わせで判定が裏返るか見てください。
全件を走るのは見つからなかったときだけです。手元の試しは大抵見つかるので速く感じますが、遅くなるのは「無いものを探した」ときです。
1 / 1
コンピューターサイエンス:アルゴリズム / OS / ネットワーク / DB - 二分探索 (反復版)
1 文字変えると答えが変わる
書き方を切り替えて、同じ配列と同じ探す値のまま表の行がどう変わるか見てください。
この取りこぼしは大きい配列では表に出ません。要素 1 個、先頭、末尾の 3 つを手でなぞったかどうかで、バグが残るかが決まります。
1 / 1
コンピューターサイエンス:アルゴリズム / OS / ネットワーク / DB - 二分探索 (再帰版)
区間を覚えているのは誰か
ステップを進めて、左の変数と右の引数が同じ数字を持つところを見てください。
引数で渡すのは index だけにしてください。配列そのものを切って渡すと、コピーが log n 回起きて、速いはずの取り柄が消えます。
1 / 1
コンピューターサイエンス:アルゴリズム / OS / ネットワーク / DB - lower_bound (最初に >= target の位置)
指しているのは要素ではなく、すきま
5 の個数を増やして、2 本の矢印のどちらが動くか見てください。
戻り値は n になることがあります。位置として挿入に使うぶんには正しく、そのまま arr の添字にすると範囲外です。どちらで使うかを先に決めてください。
1 / 1
コンピューターサイエンス:アルゴリズム / OS / ネットワーク / DB - ピーク要素検索
並んでいなくても半分に切れる
配列と切る場所を動かして、残った側にいつもピークが入っているか確かめてください。
最大値が欲しいなら全部見るしかありません。ピークは 1 つ返せば正解、と問題をゆるめた瞬間に O(n) が O(log n) に変わります。
1 / 1
コンピューターサイエンス:アルゴリズム / OS / ネットワーク / DB - 回転ソート配列での探索
先に見るのは target ではない
回転を動かして、並んでいるかたまりが左右どちらに移るか見てください。
回転しているかを先に調べる必要はありません。回転が無い配列でも同じコードが通るので、判定を足すほど分岐が増えて壊れます。
1 / 1
コンピューターサイエンス:アルゴリズム / OS / ネットワーク / DB - バブルソート実装
1 周ごとに右端が 1 つ決まる
周の数を進めて、比べる範囲が右から縮んでいくところを見てください。
1 周まわって 1 度も交換しなかったら、その時点で抜けてよいということです。この判定を足すだけで、整列済みに近い入力は 1 周で終わります。
1 / 1
コンピューターサイエンス:アルゴリズム / OS / ネットワーク / DB - 選択ソート
交換は n - 1 回で足りる
選択とバブルを切り替えて、比較の本数はそのままに交換の棒だけが変わるのを見てください。
交換が少ないのは得ですが代償があります。遠くの最小値を先頭まで引っ張るので、同じ値どうしの元の順番は壊れます。
1 / 1
コンピューターサイエンス:アルゴリズム / OS / ネットワーク / DB - 挿入ソート
並びかけの入力ほど手が減る
乱れを小さいほうへ動かして、右へずらす回数がどこまで減るか見てください。
遅いはずの挿入ソートが Python の sorted の中で今も動いています。小さい配列や並びかけの区間では、これがいちばん速いからです。
1 / 1
コンピューターサイエンス:アルゴリズム / OS / ネットワーク / DB - マージソート
小さいほうから 1 つずつ取る
手順を 1 手ずつ進めて、左右どちらの先頭が取られたのかを見てください。
取る側を決める比較を <= から < に変えると、同じ値のとき右が先に出ます。安定かどうかは等号 1 文字で決まります。
1 / 1
コンピューターサイエンス:アルゴリズム / OS / ネットワーク / DB - クイックソート
軸の選び方で木の形が変わる
本文の実装は中央を軸に取ります。この図解は先頭を軸にした場合なので、入力を整列済みへ切り替えて木の形の違いを見てください。
最悪が出るのはぐちゃぐちゃの入力ではなく、整列済みのほうです。すでに並んだデータほど本番では普通に流れてきます。
1 / 1
コンピューターサイエンス:アルゴリズム / OS / ネットワーク / DB - カウントソート
比べないかわりに、マスが要る
いちばん大きい値を動かして、比較が 0 回のまま count のマスだけが増えるのを見てください。
値の幅が広いから使えない、で終わりではありません。桁ごとに分けて同じことを繰り返せば基数ソートになり、大きな整数でも比較なしで並びます。
1 / 1
コンピューターサイエンス:アルゴリズム / OS / ネットワーク / DB - 比較関数つきソート
鍵を変えると並びが変わる
先頭の値を動かして、3 つの鍵それぞれで行き先がどう違うか見てください。
比較関数が返すのは真偽ではなく符号です。a < b と書くと true が 1 と読まれて、後ろへ回せという指示になってしまいます。
1 / 1
コンピューターサイエンス:アルゴリズム / OS / ネットワーク / DB - 長方形クラス(面積と周長)
同じ 2 つの数から、2 つの答えが出る
幅と高さのスライダーを動かして、マスの数と辺の数が同時に変わるのを見てください。
幅と高さを 1 か所に持たせておくと、あとから対角線や縦横比が要るようになってもメソッドを 1 つ足すだけで済みます。バラの変数で持つと、どの幅がどの高さと組なのかを呼ぶ側が覚え続けることになります。
1 / 1
コンピューターサイエンス:アルゴリズム / OS / ネットワーク / DB - スタッククラス(push と pop)
空で 1 回多く pop すると
pop を最後まで進めてから、言語を Python と JavaScript で切り替えてみてください。
空で取り出したとき、Python はその場で落ち、JavaScript は undefined を返して黙って先に進みます。落ちるほうが実は親切で、undefined は数十行あとの関係なさそうな場所で症状が出ます。
1 / 1
コンピューターサイエンス:アルゴリズム / OS / ネットワーク / DB - キュークラス(enqueue と dequeue)
先頭を抜くと、後ろが全部ずれる
並んでいる数を増やしてから、抜く場所を先頭と末尾で切り替えてください。
1 件ずつなら誤差ですが、キューは秒間に何千件も流れる場所で使われます。標準の deque が速いのは賢い並べ替えをしているからではなく、先頭を消さずに頭の位置だけをずらしているからです。
1 / 1
コンピューターサイエンス:アルゴリズム / OS / ネットワーク / DB - 単方向リンクリスト
繋ぎ替えは速い、たどるのは遅い
本文で作る Node の連結がこの下の段です。やりたいことを先頭に挿入と 3 番目を読むで切り替えて、上の配列と手数が逆になるのを見てください。
面接ではリンクリストが主役ですが、実務でまず選ばれるのは配列のほうです。CPU は連続したメモリを先読みするので、手数で勝っていても実測では負けることがあります。
1 / 1
コンピューターサイエンス:アルゴリズム / OS / ネットワーク / DB - 二分探索木 (BST) への挿入
入れる順番で木の形が変わる
挿入した数を進めながら、入れる順番を 2 つ切り替えて、取り出した並びは同じままなのを確かめてください。
本番で流れてくるデータは、たいてい ID 順や日付順にもう並んでいます。棒のような形は珍しい事故ではなく既定で起きるほうで、AVL 木や赤黒木は最初からその前提で作られています。
1 / 1
コンピューターサイエンス:アルゴリズム / OS / ネットワーク / DB - カウンタクラス(機能合成)
戻り値を決めているのは直前の状態
操作を 1 つずつ進めて、同じ inc なのに返る値が毎回違うところを見てください。
value を外からも書き換えられるようにした瞬間、値がおかしくなったとき疑う場所がクラスの外全部に広がります。メソッド経由だけに絞ると、探す場所は 5 つのメソッドの中だけで済みます。
1 / 1
コンピューターサイエンス:アルゴリズム / OS / ネットワーク / DB - メモ化フィボナッチ
2 回目の呼び出しは読むだけ
計算を 1 手ずつ進めて、2 回目の fib(3) が計算されずに読まれるだけになるのを見てください。
この memo は関数の中にあるから安全です。外に出して使い回すと、前回の呼び出しの値が残ったまま次の計算に混ざります。
1 / 1
コンピューターサイエンス:アルゴリズム / OS / ネットワーク / DB - DP配列でフィボナッチ
覚えておくのは直前の 2 つだけ
変数 2 本に圧縮を入れて、n を伸ばしても点いたままのマスが 2 つで止まるのを見てください。
前回のメモ化と答えは同じですが、差が出るのは n が大きいときです。再帰版は答えを出す前に、Python なら 1000 段でスタックが先に尽きます。
1 / 1
コンピューターサイエンス:アルゴリズム / OS / ネットワーク / DB - 階段の登り方
階段の答えは 1 つ先のフィボナッチ
段数 n を動かして、階段の上の数字が下の数列のどこと重なるか見てください。
同じ数列なのに位置が 1 つずれます。フィボナッチと同じと覚えて f(2) を 1 にすると、そこから先が全部ずれたまま答えが出ます。
1 / 1
コンピューターサイエンス:アルゴリズム / OS / ネットワーク / DB - コイン両替最小枚数
大きい順に取ると損をする組がある
コインの額面を 1 3 4 に切り替えて、金額 6 で上下の枚数が割れるところを見てください。
日本の硬貨は大きい順に取れば必ず最小になるので、貪欲でも一生気づけません。額面が自分たちで決めた値のときだけ、静かに 1 枚多い答えが出ます。
1 / 1
コンピューターサイエンス:アルゴリズム / OS / ネットワーク / DB - 0/1 ナップサック問題
同じ品物は 2 個目が無い
容量を動かしてから、同じ品物を何個でもを入れて、同じ容量で価値がどう変わるか見てください。
この 2 つを分けているのは表を埋める向きです。1 次元に圧縮したとき容量を昇順で回すと、更新済みの自分を読んで同じ品物を何個でも詰められる側になります。
1 / 1
コンピューターサイエンス:アルゴリズム / OS / ネットワーク / DB - 最長共通部分列 (LCS)
同じ 3 文字でも順番で答えが変わる
下の文字列 b を ace から aec、eca と替えて、交差せずに引ける線が減っていくのを見てください。
表を埋めて出るのは長さだけで、どの文字が残ったかは書かれていません。中身が欲しいときは、埋めた表を右下から逆に辿り直す手順を別に書きます。
1 / 1
コンピューターサイエンス:アルゴリズム / OS / ネットワーク / DB - ソート済み 2 配列のマージ
残った側は比べずに繋ぐ
b を短くして、while を抜けたあとに残る側が b から a へ入れ替わるのを見てください。
残りをそのまま繋ぐ 1 行を忘れても、長さが同じ入力なら答えが合ってしまいます。落ちるのは長さの違う入力で、しかも末尾だけが欠けるので気づきにくいです。
1 / 1
コンピューターサイエンス:アルゴリズム / OS / ネットワーク / DB - 配列の k 回転
k は 5 個ぶんで一巡する
k を 12 まで動かして、長さ 5 を越えたところから並びが繰り返すのを見てください。
余りを取り忘れても答えは合います。遅いだけです。本当に止まるのは空配列のほうで、n が 0 だと k % n が 0 除算になります。長さを見るより先に空かどうかを弾いてください。
1 / 1
コンピューターサイエンス:アルゴリズム / OS / ネットワーク / DB - カッコの妥当性
壊れ方は 3 通りある
壊れ方を 3 つ切り替えて、false が決まる時点が毎回違うのを見てください。
閉じ忘れだけは、読んでいる途中で一度も間違いが起きません。最後にスタックが空かを確かめる 1 行を落とすと、この 1 通りだけが素通りします。
1 / 1
コンピューターサイエンス:アルゴリズム / OS / ネットワーク / DB - ローマ数字を整数に
符号は次の文字が決める
見る位置 i を末尾まで動かして、引くか足すかがどこで決まるか見てください。
読む側は自分 1 文字では符号を決められず、必ず次を覗きます。だから末尾だけは覗く先がなく、i + 1 の範囲チェックを落とすとそこで落ちます。
1 / 1
コンピューターサイエンス:アルゴリズム / OS / ネットワーク / DB - 整数をローマ数字に
例外を表に入れると迷わなくなる
値表から 9 と 4 を外して、同じ記号が 4 回並んでしまうのを見てください。
書く側に先読みは要りません。4 と 9 を値表の行にした瞬間、大きい順に取るだけで正しくなります。判断をコードから消して表へ移す、が貪欲法の効かせ方です。
1 / 1
コンピューターサイエンス:アルゴリズム / OS / ネットワーク / DB - 雨水を溜める
水位を決めるのは低いほうの壁
見る列 i を動かして、水位を決めている壁が左から右へ入れ替わるのを見てください。
片側だけ見て水位を決めると、反対側が抜けている場所まで溜めてしまいます。min を max と書き間違えたときも例外は出ず、答えが静かに大きくなるだけです。
1 / 1