231. Power of Two
Problem Description
Given an integer n
, you need to determine if it is a power of two. Return true
if n
can be expressed as 2^x
where x
is some integer, otherwise return false
.
For example:
n = 1
returnstrue
because1 = 2^0
n = 16
returnstrue
because16 = 2^4
n = 3
returnsfalse
because there's no integerx
such that2^x = 3
The solution uses a clever bit manipulation trick. Powers of two have exactly one bit set to 1
in their binary representation (like 1000
for 8, 10000
for 16). When we compute n & (n-1)
, this operation removes the rightmost 1
bit from n
. For powers of two, since there's only one 1
bit, this operation results in 0
. The solution checks if n > 0
(to handle negative numbers and zero) and if n & (n-1) == 0
to determine if n
is a power of two.
Intuition
Let's think about what makes a number a power of two in binary representation. Powers of two have a unique pattern:
1 = 2^0 = 0001
2 = 2^1 = 0010
4 = 2^2 = 0100
8 = 2^3 = 1000
16 = 2^4 = 10000
Notice that each power of two has exactly one bit set to 1
, and all other bits are 0
. This is the key insight.
Now, what happens when we subtract 1 from a power of two? Let's see:
8 = 1000
, and8 - 1 = 7 = 0111
16 = 10000
, and16 - 1 = 15 = 01111
4 = 0100
, and4 - 1 = 3 = 0011
When we subtract 1 from a power of two, all the bits after the single 1
bit get flipped to 1
, and the original 1
bit becomes 0
.
So when we perform the bitwise AND operation n & (n-1)
:
- For
8
:1000 & 0111 = 0000
- For
16
:10000 & 01111 = 00000
- For
4
:0100 & 0011 = 0000
The result is always 0
for powers of two! This happens because there's no overlapping 1
bits between n
and n-1
when n
is a power of two.
For non-powers of two, there will be multiple 1
bits, so n & (n-1)
won't be zero. For example, 6 = 0110
and 5 = 0101
, so 6 & 5 = 0100
, which is not zero.
This elegant bit manipulation trick allows us to check if a number is a power of two in constant time with just one operation.
Solution Approach
The solution implements the bit manipulation technique where we use the expression n & (n - 1)
to check if a number is a power of two.
The implementation consists of two key conditions:
-
Check if
n > 0
: This handles edge cases wheren
is negative or zero. Negative numbers and zero cannot be powers of two, so we need to filter them out first. -
Check if
(n & (n - 1)) == 0
: This is the core bit manipulation check. As explained in the reference approach, the operationn & (n - 1)
eliminates the rightmost1
bit in the binary representation ofn
. Since powers of two have exactly one1
bit in their binary form, this operation will result in0
for all powers of two.
The algorithm works as follows:
- When
n
is a power of two (like8 = 1000
in binary), subtracting 1 gives us7 = 0111
in binary - The bitwise AND between
1000
and0111
results in0000
- This pattern holds for all powers of two
For non-powers of two:
- Consider
n = 6 = 0110
in binary n - 1 = 5 = 0101
in binaryn & (n - 1) = 0110 & 0101 = 0100
, which is not zero
The time complexity is O(1)
since we're performing a constant number of operations regardless of the input size. The space complexity is also O(1)
as we only use a fixed amount of extra space.
This bit manipulation approach is more efficient than alternative methods like repeatedly dividing by 2 or using logarithms, as it solves the problem with just a single bitwise operation.
Ready to land your dream job?
Unlock your dream job with a 5-minute evaluator for a personalized learning plan!
Start EvaluatorExample Walkthrough
Let's walk through the solution with n = 8
to see how the bit manipulation works:
-
First, check if n > 0:
8 > 0
✓ (passes the first condition)
-
Convert to binary representation:
n = 8
in binary is1000
n - 1 = 7
in binary is0111
-
Perform the bitwise AND operation:
n = 1000 n - 1 = 0111 ----------- n & (n-1) = 0000
- Each bit position is ANDed:
- Position 3:
1 & 0 = 0
- Position 2:
0 & 1 = 0
- Position 1:
0 & 1 = 0
- Position 0:
0 & 1 = 0
- Position 3:
- Result:
0000
which equals0
- Each bit position is ANDed:
-
Check if (n & (n-1)) == 0:
0 == 0
✓ (passes the second condition)- Since both conditions are true, return
true
Now let's contrast this with a non-power of two, n = 6
:
-
Check if n > 0:
6 > 0
✓ -
Binary representation:
n = 6
in binary is0110
n - 1 = 5
in binary is0101
-
Perform the bitwise AND:
n = 0110 n - 1 = 0101 ----------- n & (n-1) = 0100
- Result:
0100
which equals4
(not zero!)
- Result:
-
Check if (n & (n-1)) == 0:
4 == 0
✗ (fails the second condition)- Return
false
The key insight: powers of two have only one 1
bit, so when we subtract 1, all bits flip from that position downward, creating no overlap when ANDed together.
Solution Implementation
1class Solution:
2 def isPowerOfTwo(self, n: int) -> bool:
3 """
4 Determines if a given integer is a power of two.
5
6 A power of two in binary has only one bit set to 1.
7 For example: 1 (0001), 2 (0010), 4 (0100), 8 (1000)
8
9 The trick: n & (n-1) removes the rightmost set bit.
10 If n is a power of two, it has only one set bit,
11 so n & (n-1) will be 0.
12
13 Args:
14 n: The integer to check
15
16 Returns:
17 True if n is a power of two, False otherwise
18 """
19 # Check if n is positive (negative numbers and 0 cannot be powers of 2)
20 # AND check if n has only one bit set (using bitwise AND with n-1)
21 return n > 0 and (n & (n - 1)) == 0
22
1class Solution {
2 /**
3 * Determines if a given integer is a power of two.
4 *
5 * A number is a power of two if it has exactly one bit set in its binary representation.
6 * For example: 1 (2^0) = 0001, 2 (2^1) = 0010, 4 (2^2) = 0100, 8 (2^3) = 1000
7 *
8 * The algorithm uses a bit manipulation trick:
9 * - If n is a power of two, it has only one bit set to 1
10 * - Subtracting 1 from n flips all the bits after the rightmost set bit (including the set bit)
11 * - Therefore, n & (n-1) will be 0 only if n is a power of two
12 *
13 * Example: n = 8 (1000 in binary)
14 * n - 1 = 7 (0111 in binary)
15 * n & (n-1) = 1000 & 0111 = 0000 (equals 0, so 8 is a power of two)
16 *
17 * @param n The integer to check
18 * @return true if n is a power of two, false otherwise
19 */
20 public boolean isPowerOfTwo(int n) {
21 // Check if n is positive (negative numbers and zero cannot be powers of two)
22 // AND check if n has only one bit set using the bit manipulation trick
23 return n > 0 && (n & (n - 1)) == 0;
24 }
25}
26
1class Solution {
2public:
3 /**
4 * Determines if a given integer is a power of two.
5 *
6 * A number is a power of two if it has exactly one bit set in its binary representation.
7 * For example: 1 (2^0) = 0001, 2 (2^1) = 0010, 4 (2^2) = 0100, 8 (2^3) = 1000
8 *
9 * The algorithm uses a bit manipulation trick:
10 * - If n is a power of two, it has exactly one bit set
11 * - n - 1 will flip all bits after the rightmost set bit (including the set bit itself)
12 * - n & (n - 1) will be 0 only if n is a power of two
13 *
14 * Example: n = 8 (1000 in binary)
15 * n - 1 = 7 (0111 in binary)
16 * n & (n - 1) = 1000 & 0111 = 0000
17 *
18 * @param n The integer to check
19 * @return true if n is a power of two, false otherwise
20 */
21 bool isPowerOfTwo(int n) {
22 // Check if n is positive (negative numbers and 0 cannot be powers of two)
23 // AND check if n has exactly one bit set using the bit manipulation trick
24 return n > 0 && (n & (n - 1)) == 0;
25 }
26};
27
1/**
2 * Determines if a given number is a power of two.
3 *
4 * A power of two has only one bit set in its binary representation.
5 * Using bit manipulation: n & (n - 1) removes the rightmost set bit.
6 * If n is a power of two, this operation results in 0.
7 *
8 * @param n - The number to check
9 * @returns true if n is a power of two, false otherwise
10 */
11function isPowerOfTwo(n: number): boolean {
12 // Check if n is positive (powers of two are positive)
13 // AND check if n has only one bit set using bitwise operation
14 return n > 0 && (n & (n - 1)) === 0;
15}
16
Time and Space Complexity
The time complexity is O(1)
because the algorithm performs a fixed number of operations regardless of the input size. It only executes:
- One comparison operation (
n > 0
) - One subtraction operation (
n - 1
) - One bitwise AND operation (
n & (n - 1)
) - One equality check (
== 0
)
All these operations are constant time operations that don't depend on the magnitude of n
.
The space complexity is O(1)
because the algorithm uses only a constant amount of extra space. No additional data structures are created, and the space usage doesn't grow with the input size. The function only uses the input parameter n
and performs in-place bit manipulation without requiring any auxiliary space.
Common Pitfalls
1. Forgetting to Check for Non-Positive Numbers
One of the most common mistakes is omitting the n > 0
check and only relying on the bit manipulation (n & (n - 1)) == 0
.
Why this is a problem:
- For
n = 0
: The expression0 & (-1)
equals0
, which would incorrectly returntrue
- For negative numbers: Some implementations might behave unexpectedly with negative integers in bitwise operations
Incorrect Implementation:
def isPowerOfTwo(self, n: int) -> bool:
# Missing the n > 0 check!
return (n & (n - 1)) == 0
Correct Implementation:
def isPowerOfTwo(self, n: int) -> bool:
return n > 0 and (n & (n - 1)) == 0
2. Integer Overflow in Alternative Approaches
When using iterative multiplication or division approaches, developers might encounter overflow issues with very large numbers.
Problematic Alternative:
def isPowerOfTwo(self, n: int) -> bool:
if n <= 0:
return False
power = 1
while power < n:
power *= 2 # Can overflow for large n
return power == n
Better Approach: Stick with the bit manipulation solution which avoids overflow entirely.
3. Misunderstanding the Bit Operation
Some developers confuse the operation and use n & (n + 1)
instead of n & (n - 1)
, or use other incorrect bitwise operations.
Common Mistakes:
# Wrong: Using n + 1 instead of n - 1 return n > 0 and (n & (n + 1)) == 0 # Wrong: Using OR instead of AND return n > 0 and (n | (n - 1)) == 0 # Wrong: Checking if result equals 1 instead of 0 return n > 0 and (n & (n - 1)) == 1
4. Edge Case with n = 1
While the bit manipulation solution handles this correctly, developers implementing alternative solutions sometimes forget that 1
is a power of two (2^0 = 1
).
Example of Incorrect Logic:
def isPowerOfTwo(self, n: int) -> bool:
if n <= 1: # Wrong! This excludes 1
return False
# ... rest of the logic
The bit manipulation approach elegantly handles all these cases without special treatment, making it both efficient and less error-prone.
What are the most two important steps in writing a depth first search function? (Select 2)
Recommended Readings
Recursion Recursion is one of the most important concepts in computer science Simply speaking recursion is the process of a function calling itself Using a real life analogy imagine a scenario where you invite your friends to lunch https assets algo monster recursion jpg You first call Ben and ask
Math for Technical Interviews How much math do I need to know for technical interviews The short answer is about high school level math Computer science is often associated with math and some universities even place their computer science department under the math faculty However the reality is that you
Coding Interview Patterns Your Personal Dijkstra's Algorithm to Landing Your Dream Job The goal of AlgoMonster is to help you get a job in the shortest amount of time possible in a data driven way We compiled datasets of tech interview problems and broke them down by patterns This way
Want a Structured Path to Master System Design Too? Don’t Miss This!