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 = 1returnstruebecause1 = 2^0n = 16returnstruebecause16 = 2^4n = 3returnsfalsebecause there's no integerxsuch 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 = 00012 = 2^1 = 00104 = 2^2 = 01008 = 2^3 = 100016 = 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 = 011116 = 10000, and16 - 1 = 15 = 011114 = 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 wherenis 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 rightmost1bit in the binary representation ofn. Since powers of two have exactly one1bit in their binary form, this operation will result in0for all powers of two.
The algorithm works as follows:
- When
nis a power of two (like8 = 1000in binary), subtracting 1 gives us7 = 0111in binary - The bitwise AND between
1000and0111results in0000 - This pattern holds for all powers of two
For non-powers of two:
- Consider
n = 6 = 0110in binary n - 1 = 5 = 0101in 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 = 8in binary is1000n - 1 = 7in 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:
0000which 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 = 6in binary is0110n - 1 = 5in binary is0101
-
Perform the bitwise AND:
n = 0110 n - 1 = 0101 ----------- n & (n-1) = 0100- Result:
0100which 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
221class 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}
261class 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};
271/**
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}
16Time 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.
How does quick sort divide the problem into subproblems?
Recommended Readings
Recursion If you prefer videos here's a video that explains recursion in a fun and easy way 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 him
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!