半分の数の答えを使い回し、0 から n までの 1 のビットの数を並べる

0 から n までの各数について、2 進で書いたときの 1 の数を並べて返します。i を 1 ビット右へずらした数の答えはもう出ているので、それにいちばん下のビットを足すだけで次々に埋まる練習です。

海外で定番の問題リスト 4 本には入っていません

問題

整数 n を受け取ります。長さ n + 1 の並び out を作り、out[i] に「i を 2 進で書いたときの 1 の数」を入れて返す関数を書いてください。i は 0 から n までです。

  • 1 つの数ごとにビットを全部数える書き方ではなく、全体を O(n) の時間で埋める書き方を目指してください
  • n は 0 以上 100000 以下です

入力と出力の例

例 1

0 から 6 は、2 進で 0、1、10、11、100、101、110 です。

n = 6
[0, 1, 1, 2, 1, 2, 2]

例 2

n が 0 なら、0 の分だけの並びです。

n = 0
[0]

例 3

8 は 1000 で 1 は 1 つ、9 は 1001 で 2 つです。

n = 9
[0, 1, 1, 2, 1, 2, 2, 3, 1, 2]

面接での聞かれ方

面接では、ビット演算と動的計画法をつなぐ問題として出されます。

  • 「0 から n までの各数の 1 のビットの数を返してください」
  • 数ごとに数える書き方を見せると、「全体を O(n) にできますか?」と続きます
  • 「前の答えのどれを使えば、次の答えが出ますか?」と、手がかりをもらえることもあります

前に出した答えを使い回せる形に気づけるかが見られています。

ヒント

まだ開いていません

付箋は 3 枚。下の段ほど答えに近づきます

  1. ヒント 2

  2. ヒント 3答えに近い

アルゴリズムのチートシートの「配列と文字列」に、この型の要点を表とコードでまとめています。

配列と文字列の問題は、全部の組を調べると手間が大きくなる所を、窓や左右の添字で減らす形が多いです。

main.py
def counting_bits(n: int) -> list[int]:
    """
    Goal: 何を返すか

    idea1: まず思いつく案
    -> runtime: O(?)  space: O(?)

    idea2: もっと速い案
    -> runtime: O(?)  space: O(?)

    edge case: 空、1 つだけ、など
    """
    # ここに書きます
    pass


# 「実行」を押すと、この行の結果が出ます
print(counting_bits(6))

できているか「例で確かめる」を押すと、問題の例を全部この関数に渡して、通ったかをここに出します