How to Check if a Binary Representation is a Palindrome in Python
A binary palindrome is a number whose binary representation reads the same forwards and backwards. For example, 5 in binary is 101, and 9 is 1001, both are palindromes.
This guide covers multiple approaches, from simple string manipulation to efficient bit-level operations.
Using String Slicing
Python's string slicing [::-1] makes palindrome checking straightforward. Convert the number to binary, remove the 0b prefix, and compare with its reverse.
def is_binary_palindrome(n: int) -> bool:
"""Check if binary representation of n is a palindrome."""
binary_str = bin(n)[2:] # Remove '0b' prefix
return binary_str == binary_str[::-1]
# Test cases
print(is_binary_palindrome(5)) # True (101)
print(is_binary_palindrome(9)) # True (1001)
print(is_binary_palindrome(10)) # False (1010)
print(is_binary_palindrome(0)) # True (0)
Output:
True
True
False
True
Using f-strings
An alternative approach using formatted strings:
def is_binary_palindrome_fstring(n: int) -> bool:
"""Check palindrome using f-string formatting."""
binary_str = f"{n:b}"
return binary_str == binary_str[::-1]
Using Bit Manipulation
For competitive programming or memory-constrained environments, reverse the bits mathematically without allocating strings.
def is_binary_palindrome_bitwise(n: int) -> bool:
"""Check palindrome using bit manipulation (O(1) space)."""
if n < 0:
return False
if n == 0:
return True
# Reverse the bits
original = n
reversed_n = 0
while n > 0:
reversed_n = (reversed_n << 1) | (n & 1)
n >>= 1
return reversed_n == original
print(is_binary_palindrome_bitwise(9)) # True
print(is_binary_palindrome_bitwise(10)) # False
For n = 9 (binary 1001):
- Extract last bit:
9 & 1 = 1, shift result left, add bit →reversed = 1 - Shift n right:
9 >> 1 = 4(binary100) - Extract:
4 & 1 = 0, shift and add →reversed = 10 - Continue until n = 0 →
reversed = 1001 = 9 - Compare:
9 == 9→ True
Fixed-Width Palindrome Check
Sometimes you need to check if a number is a palindrome within a specific bit width (e.g., 8-bit byte). In this case, leading zeros are significant.
def is_binary_palindrome(n: int) -> bool:
"""Check if binary representation of n is a palindrome."""
binary_str = bin(n)[2:] # Remove '0b' prefix
return binary_str == binary_str[::-1]
def is_palindrome_fixed_width(n: int, width: int = 8) -> bool:
"""Check if n is a palindrome in a fixed-width binary representation."""
if n < 0 or n >= (1 << width):
raise ValueError(f"Number must be between 0 and {(1 << width) - 1}")
binary_str = f"{n:0{width}b}"
return binary_str == binary_str[::-1]
# Without fixed width: 9 = '1001' is a palindrome
print(is_binary_palindrome(9)) # True
# With 8-bit fixed width: 9 = '00001001' is NOT a palindrome
print(is_palindrome_fixed_width(9, 8)) # False
# 129 = '10000001' IS a palindrome in 8 bits
print(is_palindrome_fixed_width(129, 8)) # True
Finding Binary Palindromes in a Range
Generate all binary palindromes within a given range:
def find_binary_palindromes(start: int, end: int) -> list:
"""Find all binary palindromes in the given range."""
palindromes = []
for n in range(start, end + 1):
binary = bin(n)[2:]
if binary == binary[::-1]:
palindromes.append((n, binary))
return palindromes
# Find palindromes from 1 to 50
results = find_binary_palindromes(1, 50)
for decimal, binary in results:
print(f"{decimal:3d} = {binary}")
Output:
1 = 1
3 = 11
5 = 101
7 = 111
9 = 1001
15 = 1111
17 = 10001
21 = 10101
27 = 11011
31 = 11111
33 = 100001
45 = 101101
Generating Binary Palindromes
Efficiently generate palindromes rather than checking every number:
def generate_binary_palindromes(max_bits: int) -> list:
"""Generate all binary palindromes up to max_bits length."""
palindromes = []
for bits in range(1, max_bits + 1):
if bits == 1:
palindromes.append(1)
else:
# Generate palindromes of this bit length
half_len = (bits + 1) // 2
for i in range(1 << (half_len - 1), 1 << half_len):
# Build palindrome from first half
half = bin(i)[2:]
if bits % 2 == 0:
palindrome = half + half[::-1]
else:
palindrome = half + half[-2::-1]
palindromes.append(int(palindrome, 2))
return sorted(palindromes)
# Generate all palindromes up to 8 bits
palins = generate_binary_palindromes(8)
print(f"Found {len(palins)} palindromes")
print(palins[:15])
Output:
Found 30 palindromes
[1, 3, 5, 7, 9, 15, 17, 21, 27, 31, 33, 45, 51, 63, 65]
Performance Comparison
import time
def is_binary_palindrome(n: int) -> bool:
"""Check if binary representation of n is a palindrome."""
binary_str = bin(n)[2:] # Remove '0b' prefix
return binary_str == binary_str[::-1]
def is_binary_palindrome_bitwise(n: int) -> bool:
"""Check palindrome using bit manipulation (O(1) space)."""
if n < 0:
return False
if n == 0:
return True
# Reverse the bits
original = n
reversed_n = 0
while n > 0:
reversed_n = (reversed_n << 1) | (n & 1)
n >>= 1
return reversed_n == original
def benchmark(func, test_range, iterations=1000):
start = time.perf_counter()
for _ in range(iterations):
for n in test_range:
func(n)
return time.perf_counter() - start
test_numbers = range(1, 1000)
print(f"String method: {benchmark(is_binary_palindrome, test_numbers):.4f}s")
print(f"Bitwise method: {benchmark(is_binary_palindrome_bitwise, test_numbers):.4f}s")
Output:
String method: 0.2659s
Bitwise method: 1.1837s
Method Comparison
| Method | Time Complexity | Space Complexity | Best For |
|---|---|---|---|
| String slicing | O(log n) | O(log n) | General use, readability |
| Bit manipulation | O(log n) | O(1) | Memory-constrained, competitive programming |
| Fixed-width | O(width) | O(width) | Hardware-specific bit patterns |
Summary
- Use string slicing (
bin(n)[2:][::-1]) for most applications. It's readable and Pythonic. - Use bit manipulation when memory is constrained or you need constant space.
- Use fixed-width formatting when leading zeros are significant (e.g., byte-level operations).
- Consider generating palindromes directly when you need many of them.