半分の 数の 答えを 使い回し、 0 から n までの 1 の ビットの 数を並べる
0 から
海外で定番の問題リスト 4 本には入っていません
問題
整数 n をn + 1 のout をout[i] に
- 1 つの
数ごとに ビットを 全部数える 書き方ではなく、 全体を O(n) の 時間で 埋める 書き方を 目指してください nは 0 以上 100000 以下です
入力と出力の例
例 1
0 から 6 は、
例 2
n が 0 なら、
例 3
8 は 1000 で 1 は 1 つ、
面接での聞かれ方
面接では、
- 「0 から n までの
各数の 1 の ビットの 数を 返してください」 - 数ごとに
数える 書き方を 見せると、 「全体を O(n) に できますか?」と続きます - 「前の
答えの どれを 使えば、 次の 答えが 出ますか?」と、 手が かりを もらえる こともあります
前に
ヒント
まだ開いていません
付箋は 3 枚。下の段ほど答えに近づきます
ヒント 2
ヒント 3答えに近い
アルゴリズムのチートシートの「配列と文字列」に、
関わる学び
配列と
まず 考える手順
段 1
まずは
段 2
i を 1 ビット右へずらしたi >> 1 は、i >> 1 は i よりout にi & 1 を
段 3
out[0] を 0 にし、out[i] = out[i >> 1] + (i & 1) で
解答
Python
Python
def counting_bits(n):
out = [0] * (n + 1)
for i in range(1, n + 1):
out[i] = out[i >> 1] + (i & 1)
return outJavaScript
JavaScript
function countingBits(n) {
const out = new Array(n + 1).fill(0);
for (let i = 1; i <= n; i++) {
out[i] = out[i >> 1] + (i & 1);
}
return out;
}Go
Go
func countingBits(n int) []int {
out := make([]int, n+1)
for i := 1; i <= n; i++ {
out[i] = out[i>>1] + i&1
}
return out
}Go では & が + よりout[i>>1] + (i & 1) と+ が
計算量
- 時間は O(n) です。
1 つの 数に つき 1 回の計算です - 使う
記憶は、 答えの 並びを 除けば O(1) です out[i] = out[i & (i - 1)] + 1(いちばん下の 1 を消した 数の 答えに 1 を 足す) と 書いても、 同じく O(n) です
よく ある間違い
- Python や JavaScript で
括弧を落とす。 out[i >> 1] + i & 1は(out[i >> 1] + i) & 1と読まれ、 0 か 1 しか 入りません - 長さを n にする。 0 から n までは n + 1 個です。
例 2 で 空の 並びを 返してしまいます - i を 0 から
回して out[0 >> 1]を読む。 0 では自分 自身を 読むだけなので害は ありませんが、 0 は 最初から 0 と 決めて おき、 1 から 回すと 読みやすくなります
解答を動かした版 Python 3.14.7Node.js 24.22.1Go 1.24.2確認日 2026年11月8日
面接での 話し方の例
書き始める
「i を 1 ビット右へずらした数は i より
小さいので、 その 答えは もう 出ています。 i の 1 の 数は、 その 答えに、 落としたいちばん下の ビットを 足した値です。 0 から 順に 埋めれば、 1 つの 数に つき 1 回の 計算で、 全体が O(n) です。」
書き終えたら、
「例 1 の 6 を
たどります。 6 は 110 で、 右へずらすと 3 (11) です。 3 の 答えは 2 で、 6 の いちばん下の ビットは 0 なので、 6 の 答えは 2 です。 5 は 101 で、 右へずらすと 2 (10) の 答え 1 に、 下の ビットの 1 を 足して 2 です。」