Pythonで0からnまでの全数値のセットビット総数をカウントするプログラム
問題の概要
ある整数 num が与えられたとき、0 ≤ i ≤ num の範囲に含まれる各整数 i について、その2進数表現における「1」の個数(セットビット数)を求めます。
例えば、num が 5 の場合、対象となる数値は [0, 1, 2, 3, 4, 5] です。それぞれを2進数で表すと次のようになります。
- 0 → 0 → セットビット数 0
- 1 → 1 → セットビット数 1
- 2 → 10 → セットビット数 1
- 3 → 11 → セットビット数 2
- 4 → 100 → セットビット数 1
- 5 → 101 → セットビット数 2
したがって、各数値のセットビット数は [0, 1, 1, 2, 1, 2] となり、その合計値である 7 を返します。
アルゴリズム
この問題は、ビット演算を活用した動的計画法(DP)の考え方で効率的に解けます。手順は以下の通りです。
res := num + 1 個の 0 を要素にもつ配列を用意する
offset := 0 と初期化する
i を 1 から num まで順に処理する:
i & (i − 1) == 0 の場合(つまり i が2のべき乗の場合)、res[i] := 1 とし、offset := 0 にリセットする
それ以外の場合は、offset を 1 増やし、res[i] := 1 + res[offset] とする
最後に、res の全要素の合計を返す
なぜこの方法が機能するのか
ポイントは条件式 i & (i − 1) です。これは i が2のべき乗(1, 2, 4, 8, …)のときだけ結果が 0 になるビット演算です。2のべき乗の2進数表現は最上位に「1」を1つだけ持つためです。
i が2のべき乗でない場合、i は「直前の2のべき乗 + offset」という形で表せます。このとき、i のセットビット数は「先頭ビット分の 1」と「offset のセットビット数」の和になります。つまり、すでに計算済みの小さい数値の結果を再利用できるため、各数値を実質 O(1) で処理できます。
実装例
以下がPythonでの実装コードです。
class Solution:
def countBits(self, num):
result = [0] * (num + 1)
offset = 0
for i in range(1, num + 1):
if i & (i - 1) == 0:
result[i] = 1
offset = 0
else:
offset += 1
result[i] = 1 + result[offset]
return sum(result)
ob1 = Solution()
print(ob1.countBits(5))
入力
5
出力
7
計算量
このアルゴリズムは 0 から num までの各数値を一度ずつ処理するため、時間計算量は O(num)、結果を保存する配列が必要なため空間計算量も O(num) です。各数値について2進数へ変換しながらビットを数える素朴な方法(O(num log num))と比べて効率的です。
別のアプローチ:よりシンプルな漸化式
参考までに、さらに簡潔に書ける方法もあります。result[i] = result[i >> 1] + (i & 1) という関係を利用すると、「i のセットビット数 = i を1ビット右シフトした値のセットビット数 + i の最下位ビット」として計算できます。
class Solution:
def countBits(self, num):
result = [0] * (num + 1)
for i in range(1, num + 1):
result[i] = result[i >> 1] + (i & 1)
return sum(result)
-
指定した範囲内の未設定ビットを数えるPythonプログラム
正の整数とビット位置の範囲が与えられたとき、その範囲内に含まれる未設定ビット(値が「0」のビット)の個数を数える方法を解説します。 入力 : n = 50, 開始位置 = 2, 終了位置 = 5 出力 : 2 この例では、ビット位置2から5の範囲内に「0」のビットが2つ存在します。実際、50を2進数で表すと 110010 となり、下位から数えて3番目(位置2)と6番目(位置5)に該当する部分に「0」が2つ含まれています。 アルゴリズム bin() 関数を使って、整数 n を2進数の文字列に変換します。 先頭の2文字(プレフィックス 0b)を取り除きます。 文字列を反転させます。これにより
-
Pythonで数値の合計ビット数をカウントするプログラムの作成方法
まず数値を入力し、bin()関数を使ってその数値を2進数に変換します。次に出力される文字列の先頭2文字「0b」を削除し、最後に2進数文字列の長さを計算することで、合計ビット数を求めることができます。 実行例 入力:200 出力:8 解説 200の2進数表現は 11001000 です(8桁=8ビット) アルゴリズム ステップ1:数値を入力する。 ステップ2:bin()関数を使用して、数値を2進数に変換する。 ステップ3:bin()関数は出力文字列の先頭に「0b」という接頭辞を付加するため、 出力された2進数文字列から最初の2文字「0b」を削除する。 ステップ4:2進