Count Binary Palindromic Numbers

Hard
Watch on YouTube ↗

Solution

class Solution {
    public int countBinaryPalindromes(long n) {
        
        // Special case: n = 0 (only "0" is a palindrome)
        if (n == 0) 
            return 1;

        // ------------------------------------------------------------
        // Step 1: Find the number of bits in n
        // Example: n = 9 (1001 in binary) → bits = 4
        // ------------------------------------------------------------
        int bits = 64 - Long.numberOfLeadingZeros(n);

        // Start with count = 1 to include "0" as a valid palindrome
        int count = 1;

        // ------------------------------------------------------------
        // Step 2: Count all palindromes with bit-length < bits
        // Formula: 2^((len+1)/2 - 1) palindromes for each length
        // Why? First bit must be 1, remaining (halfLen-1) bits are free
        // ------------------------------------------------------------
        for (int len = 1; len < bits; len++) {
            int halfbits = (len + 1) / 2;
            int palindromes = 1 << (halfbits - 1); // 2^(halfbits-1)
            count += palindromes;
        }

        // ------------------------------------------------------------
        // Step 3: Handle palindromes with exactly 'bits' length
        // Extract prefix (first half of bits of n)
        // ------------------------------------------------------------
        int halfLen = (bits + 1) / 2;        
        long prefix = n >> (bits - halfLen); // keep top half of n

        // Smallest possible prefix (must start with '1')
        long minPrefix = (1L << (halfLen - 1));

        // Count palindromes formed by smaller prefixes than current prefix
        count += (int)(prefix - minPrefix);

        // ------------------------------------------------------------
        // Step 4: Build palindrome candidate from current prefix
        // Mirror prefix → full palindrome
        // ------------------------------------------------------------
        String s = Long.toBinaryString(prefix);
        String r;

        if (bits % 2 == 0) {
            // Even length → mirror full prefix
            r = new StringBuilder(s).reverse().toString();
        } else {
            // Odd length → skip middle bit before mirroring
            r = new StringBuilder(s.substring(0, s.length() - 1)).reverse().toString();
        }

        long candidate = Long.parseLong(s + r, 2); // binary → decimal

        // If candidate ≤ n, include it in count
        if (candidate <= n) {
            count++;
        }

        return count;
    }
}
/*

Solution Appraoch:


1 bit = 2
2 bit = 1
3 bit = 2
4 bit = 2 [1001, 1111]

// step 1 - couting all the binary palindromic numbers
Ex:

Even
_ _ _ _   = 4 bits

Odd
_ _ _ _ _ = 5 bits

halfbits = 2, 3

totalbits = len

halfbits = (len+1)/2 


1 _ _ X X
no of bits = 5


1 0 0 0 1
1 0 1 0 1
1 1 0 1 1
1 1 1 1 1

2 * 2 = 4 [permutations] = 2^(no of half bits-1)

no of binary palindromes = 4

len = total no of bits in the number
halfbits = (len+1)/2

2 ^ halfbits-1 = count of binary palindromes for bits of length len

2 ^ ((len+1)/2-1) = len bits binary palindromes

9 = 1001 = 4 bits

1 bit palindromes
2 bit palindromes
3 bit palindromes
and so on...

// Handling the numbers with same bits as n

Example:
4 bit = 1111  [halflen = 2]
5 bit = 11111 [halflen = 3]

Count the numbers with smaller prefixes but same bit length

Getting the prefix of the given number n
prefix = n >> (lenofbits - halfLen);
our prefix = 1 1  and 1 1 1

get the min prefix for this bit length
1L << (halfLen - 1)
4 bits = [1 0 ]
5 bits = [1 0 0 ]   

difference = prefix - min prefix = possible binary palindromes

5 bits = [1 0 0 _ _]   
Ex - 100XX, 101XX, 110XX


halfbits = (len+1)/2;
Example:
4 bit = 1111
5 bit = 11111


remove the mirrored half bits of this number
n >> (bits - halfbits) 

4 bit = 11
5 bit = 111

s4 = "11"
s5 = "111"

// get the palindrome using string

s4 = "1111"
s5 = "11111"  // Ex: For 11100 , prefix = 111,  palindrome = 11111
*/