2026-04-17:将数字变成二进制回文数的最少操作。用go语言,给你一个整数数组 nums。对数组里的每个位置 i,你都可以对 nums[i] 进行任意次“+1”或“-1”的调整(可以一次不做)。
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完整代码如下:
packagemainimport("fmt""math""math/bits")funcminOperations(nums[]int)[]int{fori,x:=rangenums{res:=math.MaxInt n:=bits.Len(uint(x))m:=n/2left:=x>>mforl:=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}returnnums}funcabs(xint)int{ifx<0{return-x}returnx}funcmain(){nums:=[]int{1,2,4}result:=minOperations(nums)fmt.Println(result)}Python完整代码如下:
# -*-coding:utf-8-*-importmathdefreverse_bits(v:int,width:int)->int:""" 反转整数 v 的低 width 位,返回一个宽度为 width 的位反转结果。 例如:v=6 (110b), width=3 -> 反转后为 011b = 3 """res=0foriinrange(width):res=(res<<1)|((v>>i)&1)returnresdefminOperations(nums):fori,xinenumerate(nums):res=math.inf n=x.bit_length()# 相当于 bits.Len(uint(x))m=n//2# 左半部分的位数left=x>>m# 原始左半部分fordeltain(-1,0,1):l=left+deltaifl<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]=resreturnnumsdefmain():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)intbitLen(uint32_tx){if(x==0)return0;return32-__builtin_clz(x);// GCC/Clang 内置函数}// 反转低 width 位(相当于 bits.Reverse 并右移对齐)uint32_treverseBits(uint32_tv,intwidth){uint32_tres=0;for(inti=0;i<width;++i){res=(res<<1)|((v>>i)&1);}returnres;}// 计算绝对值intabs(intx){returnx<0?-x:x;}std::vector<int>minOperations(std::vector<int>&nums){for(int&x:nums){intres=INT_MAX;uint32_tux=static_cast<uint32_t>(x);intn=bitLen(ux);intm=n/2;// 左半部分位数uint32_tleft=ux>>m;// 原始左半部分for(intdelta=-1;delta<=1;++delta){intl=static_cast<int>(left)+delta;if(l<0)continue;uint32_tul=static_cast<uint32_t>(l);// 若 n 为奇数,反转前先去掉正中间的比特(即右移 1 位)uint32_ttoReverse=ul>>(n%2);uint32_tright=reverseBits(toReverse,m);uint32_tpal=(ul<<m)|right;intdiff=abs(x-static_cast<int>(pal));if(diff<res)res=diff;}x=res;}returnnums;}intmain(){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":", ");}return0;}