Power of Two
整数 n が与えられます。n が2の累乗、つまりある非負整数 k ≥ 0 に対して n = 2^k である場合は true を返し、それ以外の場合は false を返してください。したがって、1、2、4、8 は該当しますが、0、6、およびすべての負の数は該当しません。
関数
- ninteger
- テストする整数。0 または負の数の場合もあります
- 戻り値boolean
- ある k ≥ 0 について n が 2^k に等しい場合は true、それ以外の場合は false
制約
-231 ≤ n ≤ 231-1
例
- 入力
- n = 16
- 出力
- true
- 説明
- 16 = 2 × 2 × 2 × 2 = 2^4。2進数では
10000で、1ビットだけが1です。
- 入力
- n = 24
- 出力
- false
- 説明
- 24 = 8 × 3。半分にすると12、6、そして3になり、これは奇数ですが1ではありません。2進数では24は
11000で、1ビットが2つあります。
- 入力
- n = 1
- 出力
- true
- 説明
- 1 = 2^0 なので、2 の累乗です。その2進数表現である
1には、1 のビットがちょうど1つあります。
提出時に隠しテスト+17件
発展問題
同じビット演算のテクニックを使って、ループを使わずにnが4のべき乗かどうか判定できますか?
ヒント
1つずつ開いてください。開くたびに少しずつ答えに近づきます。
2のべき乗を2進数でいくつか書いてみましょう:
1、10、100、1000。これらすべてに共通していて、6(110)にはないものは何でしょうか?2の累乗には、1のビットがちょうど1つあります。
nとn-1を2進数で比較してみましょう。1を引くと、最も低い位置にある1のビットが0に変わり、その下にあるすべての0が1に変わります。つまり、
nが2の累乗であるのは、正の数であり、かつn-1とのAND演算の結果が0になる場合に限ります。0と負の数は決して2の累乗ではないため、ビットを調べる前に符号を確認してください。
解説
2のべき乗は、2進数では決まった形をしています。16を表す10000のように、1つの1ビットの後に0が続きます。nが奇数になるまで半分にしていけば、その形を確認できます。この方法では最大31回の手順が必要です。または、n & (n-1)を使えば1回の手順で確認できます。これは最も下位の1ビットをクリアし、そのビットだけが唯一の1だった場合に限り0を残します。どちらの方法でも、符号のチェックを最初に行います。ゼロや負の数では、見た目どおりのコードが正しく動作しないためです。
数が偶数である間、2で割る
考え方
n = 2^k なら、k 回ちょうど 2 で割ると 1 になり、その途中の値はすべて偶数です。n に 1 より大きい奇数の因数がある場合、半分にする操作は 1 ではない奇数で止まります。16 の場合:16, 8, 4, 2, 1 なので、答えは true です。24 の場合:24, 12, 6, 3 となり、3 は奇数ですが 1 ではないため、答えは false です。
ループの前に n ≤ 0 なら false を返します。2 のべき乗が 0 または負になることはなく、0 は偶数であり、0 の半分も 0 のままなので、ループが 0 で終了することはありません。
各ステップで n は半分になるため、32 ビット入力でのステップ数は最大 31 回です。時間計算量は O(log n)、空間計算量は O(1) です。
アルゴリズム
n ≤ 0の場合、false を返します。nが偶数である間、2 で割ります。nが現在 1 かどうかを返します。
def isPowerOfTwo(n):
if n <= 0:
return False
while n % 2 == 0:
n //= 2
return n == 1n & (n-1) で最下位の1ビットをクリアする
考え方
2 のべき乗を2進数で書くと、1つの 1 の後にゼロが続きます。16 は 10000 です。1 を引くと、その 1 が 0 になり、その下にあるすべての 0 が 1 になります。15 は 01111 です。この2つの数には共通する 1 ビットがないため、16 & 15 は 0 です。
それ以外の正の数には、少なくとも2つの 1 ビットがあります。1 を引くと、最も下位の 1 ビットとその下のゼロだけが変化するため、それより上位の 1 ビットは両方の数に現れ、AND の結果は 0 になりません。11000 である 24 の場合、23 = 10111 となり、24 & 23 は 10000、つまり 16 です。
まず n > 0 を確認してください。0 & -1 は 0 であり、32ビット演算では -2^31 は1つの 1 ビットの後に31個のゼロが続くため、AND だけではどちらも2のべき乗と判定されてしまいます。テスト全体は比較1回、減算1回、AND 1回で、時間計算量と空間計算量は O(1) です。Lua 5.1 には AND 演算子がないため、Lua のコードでは一度に1ビットずつ AND を構築します。32ビットの n では最大31ステップです。テストは同じです。
アルゴリズム
n ≤ 0の場合、false を返します。n & (n-1)を計算します。これは、最下位の 1 ビットをクリアしたnです。- その結果が 0 かどうかを返します。
def isPowerOfTwo(n):
# One set bit: n - 1 flips it and every bit below, so the AND is 0.
return n > 0 and n & (n - 1) == 0
落とし穴と境界ケース
ビット判定は1行で済みますが、間違いのほとんどは、この判定が想定していない入力に関するものです。
- 符号チェックを省略する。
0 & (0-1)は0なので、0はAND判定を通過します。32ビット整数では、2進数表現が1ビットだけの1であるため、-2^31も通過します。どちらも false を返す必要があります。 - 0に対して半分にするループを実行する。0は偶数であり、半分にしても再び0になるため、ループは終わりません。
- 括弧を省略する。
==は&より優先順位が高いため、C、C++、JavaScriptではn & n - 1 == 0はn & ((n - 1) == 0)と解釈され、エラーにならずに誤った結果を返します。JavaとC#では型エラーとして拒否されます。(n & (n - 1)) == 0と書きましょう。 - 対数を使う。倍精度では、
log(536870912) / log(2)の計算結果は29ではなく29.000000000000004となるため、整数かどうかのチェックでは2^29を false と判定します。
よくある質問4
数値が2のべき乗かどうかを確認するには、どうすればよいですか?
n > 0 かつ n & (n-1) が 0 に等しい場合は true を返します。2 の累乗は 1 ビットがちょうど 1 つだけ立っており、1 を引くとそのビットがクリアされ、それより下位のビットだけが立つため、AND の結果は 0 になります。ビット演算を使わない場合は、n が偶数の間 2 で割り続け、最後に 1 になることを確認します。
なぜ n & (n-1) は最下位のセットビットをクリアするのでしょうか?
1を引くと、最も低位の1ビットから借りが行われます。そのビットは0になり、その下のすべての0は1になります。一方、それより上位のビットは変わりません。元の値とAND演算すると、両方で1に設定されているビットだけが残ります。これは、ちょうど上位のビットです。2のべき乗の場合、上位のビットは存在しないため、結果は0になります。
2のべき乗の時間計算量はどれくらいですか?
n & (n-1) のチェックは、時間・空間ともに O(1) で実行されます。比較1回、減算1回、AND演算1回です。半分にするループは時間計算量が O(log n) で、32ビット整数の場合、最大31ステップです。
1 は 2 のべき乗ですか?0 はどうですか?
1 は 2 の累乗です。2^0 = 1 だからです。また、その2進数表記には 1 ビットが1つあります。0 はそうではありません。整数の指数で 0 になるものはなく、1 ビットもまったくありません。負の数も 2 の累乗にはなりません。
似た問題
同じ考え方を使う問題です。2〜3問解くとパターンが身につきます。
Python
def isPowerOfTwo(n):
# ここにコードを書いてくださいケース1
ケース2
ケース3
入力
n = 16
期待値
true