2026-04-17:将数字变成二进制回文数的最少操作。用go语言,给你一个整数数组 nums。对数组里的每个位置 i,你都可以对 nums[i] 进行任意次“+1”或“-1”的调整(可以一次不做)。把某个整数改成“二进制回文数”(也就是它的二进制表示去掉前导零后,正着读和反着读完全相同),所需的最少调整次数是多少?把每个位置的最小次数依次放到结果数组 ans 中并返回,其中 ans[i] 表示把 nums[i] 变成二进制回文数的最小操作次数。
1 <= nums.length <= 5000。
1 <= nums[i] <= 5000。
输入:nums = [1,2,4]
输出:[0,1,1]
解释:
一种最优的操作集合如下:
| nums[i] | nums[i] 的二进制 | 最近的回文数 | 回文数的二进制 | 所需操作 | ans[i] |
|---|---|---|---|---|---|
| 1 | 1 | 1 | 1 | 已经是回文数 | 0 |
| 2 | 10 | 3 | 11 | 加 1 | 1 |
| 4 | 100 | 3 | 11 | 减 1 | 1 |
因此,ans = [0, 1, 1]。
题目来自力扣3766。
大体步骤
- 遍历输入的整数数组,逐个处理数组中的每一个数字,单独计算每个数字变成二进制回文数的最小操作次数。
- 对当前处理的数字,先获取它去除前导零后的二进制总位数,确定二进制回文数的构造规则:奇数位保留中间位,偶数位无中间位。
- 根据二进制总位数,拆分出二进制的左半部分数值,以该数值为中心,取前一个、本身、后一个三个候选值,用于构造回文数。
- 对每个候选左半部分,按照二进制回文规则生成完整的二进制回文数:将左半部分反转后拼接为右半部分,奇数位时保留中间位。
- 计算当前数字与每个构造出的二进制回文数的绝对差值,差值就是调整操作次数,记录最小的差值。
- 将每个数字对应的最小操作次数,按原数组顺序存入结果数组,所有数字处理完成后返回结果数组。
时间复杂度与额外空间复杂度
- 总时间复杂度:O(n),其中n是数组长度。数组每个元素仅进行固定次数的位运算、数值计算和比较,无嵌套循环,整体为线性时间复杂度。
- 总额外空间复杂度:O(1),仅使用了固定数量的临时变量存储中间结果,未开辟与输入规模相关的额外空间,结果数组属于题目要求的输出空间,不计入额外空间。
Go完整代码如下:
package main
import (
"fmt"
"math"
"math/bits"
)
func minOperations(nums []int) []int {
for i, x := range nums {
res := math.MaxInt
n := bits.Len(uint(x))
m := n / 2
left := x >> m
for l := left - 1; l <= left+1; l++ {
// 左半反转到右半
// 如果 n 是奇数,先去掉正中间的比特,再反转
right := bits.Reverse(uint(l>>(n%2))) >> (bits.UintSize - m)
pal := l<<m | int(right)
res = min(res, abs(x-pal))
}
nums[i] = res
}
return nums
}
func abs(x int) int {
if x < 0 {
return -x
}
return x
}
func main() {
nums := []int{1, 2, 4}
result := minOperations(nums)
fmt.Println(result)
}
Python完整代码如下:
# -*-coding:utf-8-*-
import math
def reverse_bits(v: int, width: int) -> int:
"""
反转整数 v 的低 width 位,返回一个宽度为 width 的位反转结果。
例如:v=6 (110b), width=3 -> 反转后为 011b = 3
"""
res = 0
for i in range(width):
res = (res << 1) | ((v >> i) & 1)
return res
def minOperations(nums):
for i, x in enumerate(nums):
res = math.inf
n = x.bit_length() # 相当于 bits.Len(uint(x))
m = n // 2 # 左半部分的位数
left = x >> m # 原始左半部分
for delta in (-1, 0, 1):
l = left + delta
if l < 0:
continue
# 如果 n 是奇数,需要先去掉正中间的比特再反转
to_reverse = l >> (n % 2)
# 反转 to_reverse 的低 m 位,得到右半部分
right = reverse_bits(to_reverse, m)
# 拼接左半和右半,构造回文数
pal = (l << m) | right
res = min(res, abs(x - pal))
nums[i] = res
return nums
def main():
nums = [1, 2, 4]
result = minOperations(nums)
print(result) # 输出: [0, 1, 1]
if __name__ == "__main__":
main()
C++完整代码如下:
#include <iostream>
#include <vector>
#include <climits>
#include <cmath>
#include <cstdint>
// 计算 x 的二进制位数(相当于 bits.Len)
int bitLen(uint32_t x) {
if (x == 0) return 0;
return 32 - __builtin_clz(x); // GCC/Clang 内置函数
}
// 反转低 width 位(相当于 bits.Reverse 并右移对齐)
uint32_t reverseBits(uint32_t v, int width) {
uint32_t res = 0;
for (int i = 0; i < width; ++i) {
res = (res << 1) | ((v >> i) & 1);
}
return res;
}
// 计算绝对值
int abs(int x) {
return x < 0 ? -x : x;
}
std::vector<int> minOperations(std::vector<int>& nums) {
for (int& x : nums) {
int res = INT_MAX;
uint32_t ux = static_cast<uint32_t>(x);
int n = bitLen(ux);
int m = n / 2; // 左半部分位数
uint32_t left = ux >> m; // 原始左半部分
for (int delta = -1; delta <= 1; ++delta) {
int l = static_cast<int>(left) + delta;
if (l < 0) continue;
uint32_t ul = static_cast<uint32_t>(l);
// 若 n 为奇数,反转前先去掉正中间的比特(即右移 1 位)
uint32_t toReverse = ul >> (n % 2);
uint32_t right = reverseBits(toReverse, m);
uint32_t pal = (ul << m) | right;
int diff = abs(x - static_cast<int>(pal));
if (diff < res) res = diff;
}
x = res;
}
return nums;
}
int main() {
std::vector<int> nums = {1, 2, 4};
std::vector<int> result = minOperations(nums);
for (size_t i = 0; i < result.size(); ++i) {
std::cout << result[i] << (i == result.size()-1 ? "\n" : ", ");
}
return 0;
}