
2026-02-07:统计二进制回文数字的数目。用go语言,给定一个不小于 0 的整数 n。考察区间 0 到 n 内的每个整数,把它用二进制表示并去掉前导零;如果该二进制串正着读和反着读都一样,则认为该整数是二进制回文数。请统计并返回在 0 到 n 范围内满足这一条件的整数个数。特别说明:把 0 的二进制表示视为 "0",也算作回文。
0 <= n <= 1000000000000000。
输入: n = 9。
输出: 6。
解释:
在范围 [0, 9] 内,二进制表示为回文数的整数 k 有:
0 → "0"
1 → "1"
3 → "11"
5 → "101"
7 → "111"
9 → "1001"
[0, 9] 中的所有其他值的二进制形式都不是回文。因此,计数为 6。
题目来自力扣3677。
left + 中间位 + reverse(left),其中 left 是前 m/2 位(向下取整),中间位就是二进制串中间那个数字。left + reverse(left)。因此我们可以按二进制位数 m 来分类统计回文数。
设 m = bits.Len(uint(n))(n≥1),若 n=0,直接返回 1。
n 的二进制有效长度是 m 位(最高位是 1)。
对于每个可能的长度 L:
实际上算法中使用一个参数 k 来简化累加:
2<<k - 1 来求得(这是奇数偶数两种情况的总和)。ans += 1 << k(对 k 的调整)。left,即 n >> (m/2)(如果 m 是偶数,就是高半部分;如果 m 是奇数,就是高 (m+1)/2 位)。1<<k(k 是前半部分除去中间位后的长度,即 (m-1)/2),最大是 left-1。left - 1<<k 个回文数的左半部分小于 n 的左半部分且长度等于 m,这些肯定小于 n。这种情况下,回文数由左半部分唯一确定。我们构造出对应的回文数:
left 和 m 的奇偶性生成右半部分:右半部分 = reverse(left) 去掉可能的中间位。(左半部分) << (m/2) | 右半部分。left = 9>>2 = 2(二进制 10),k= (4-1)/2=1,1<<1 = 2,left - 2 = 0,所以没有。总时间复杂度:O(1) 总额外空间复杂度:O(1)
.
package main
import (
"fmt"
"math/bits"
)
func countBinaryPalindromes(n int64)int {
if n == 0 {
return1
}
m := bits.Len(uint(n))
k := (m - 1) / 2
// 二进制长度小于 m
ans := 2<<k - 1
if m%2 == 0 {
ans += 1 << k
}
// 二进制长度等于 m,且回文数的左半小于 n 的左半
left := n >> (m / 2)
ans += int(left) - 1<<k
// 二进制长度等于 m,且回文数的左半等于 n 的左半
right := bits.Reverse32(uint32(left>>(m%2))) >> (32 - m/2)
if left<<(m/2)|int64(right) <= n {
ans++
}
return ans
}
func main() {
n := int64(9)
result := countBinaryPalindromes(n)
fmt.Println(result)
}

.
# -*-coding:utf-8-*-
def count_binary_palindromes(n: int) -> int:
if n == 0:
return1
# 计算二进制长度
m = n.bit_length()
k = (m - 1) // 2
# 二进制长度小于 m
ans = (2 << k) - 1
if m % 2 == 0:
ans += 1 << k
# 二进制长度等于 m,且回文数的左半小于 n 的左半
left = n >> (m // 2)
ans += left - (1 << k)
# 二进制长度等于 m,且回文数的左半等于 n 的左半
# 处理右半部分的反转
if m % 2 == 1:
# 奇数长度,去掉中间位
right_part = left >> 1
else:
right_part = left
# 反转右半部分
# 计算反转后的右半部分
reversed_right = 0
temp = right_part
for i in range(m // 2):
reversed_right = (reversed_right << 1) | (temp & 1)
temp >>= 1
# 构建完整的回文数
if m % 2 == 0:
palindrome = (left << (m // 2)) | reversed_right
else:
# 奇数长度,中间位是 left 的最低位
palindrome = ((left >> 1) << (m // 2 + 1)) | ((left & 1) << (m // 2)) | reversed_right
# 如果回文数小于等于 n,则加1
if palindrome <= n:
ans += 1
return ans
def main():
n = 9
result = count_binary_palindromes(n)
print(result)
if __name__ == "__main__":
main()
.
#include <iostream>
#include <cstdint>
#include <bit>
// 用于反转 32 位整数的辅助函数(C++20 之前没有 std::reverse 用于整数)
uint32_t reverseBits32(uint32_t x) {
// 使用分治法反转位
x = ((x & 0x55555555) << 1) | ((x >> 1) & 0x55555555);
x = ((x & 0x33333333) << 2) | ((x >> 2) & 0x33333333);
x = ((x & 0x0F0F0F0F) << 4) | ((x >> 4) & 0x0F0F0F0F);
x = ((x & 0x00FF00FF) << 8) | ((x >> 8) & 0x00FF00FF);
x = (x << 16) | (x >> 16);
return x;
}
int countBinaryPalindromes(int64_t n) {
if (n == 0) {
return1;
}
// 计算二进制长度
int m = 64 - __builtin_clzll(static_cast<uint64_t>(n));
int k = (m - 1) / 2;
// 二进制长度小于 m
int ans = (2 << k) - 1;
if (m % 2 == 0) {
ans += 1 << k;
}
// 二进制长度等于 m,且回文数的左半小于 n 的左半
int64_t left = n >> (m / 2);
ans += static_cast<int>(left - (1LL << k));
// 二进制长度等于 m,且回文数的左半等于 n 的左半
uint32_t right = reverseBits32(static_cast<uint32_t>(left >> (m % 2))) >> (32 - m / 2);
if ((left << (m / 2)) | static_cast<int64_t>(right) <= n) {
ans++;
}
return ans;
}
int main() {
int64_t n = 9;
int result = countBinaryPalindromes(n);
std::cout << result << std::endl;
return0;
}
