题意
传送门 LeeCode 1611. 使整数变为 0 的最少操作次数
题解
先考虑基本变换,定义
F
(
i
)
F(i)
F(i) 为使
0
0
0 变为
2
i
2^i
2i 或使
2
i
2^i
2i 变为
0
0
0 的操作次数,那么需要
F
(
i
−
1
)
F(i-1)
F(i−1) 次操作使将
0
0
0 变为
2
i
−
1
2^{i-1}
2i−1,将
i
i
i 位异或
1
1
1 后,在通过
F
(
i
−
1
)
F(i-1)
F(i−1) 次操作使
2
i
−
1
2^{i-1}
2i−1 变为
0
0
0。则有
{
F
(
i
)
=
2
F
(
i
−
1
)
+
1
F
(
0
)
=
1
\begin{cases} F(i)=2F(i-1)+1 \\ F(0)=1 \\ \end{cases}
{F(i)=2F(i−1)+1F(0)=1 求解得到
F
(
i
)
=
2
i
+
1
−
1
F(i)=2^{i+1}-1
F(i)=2i+1−1。
目标是将高位的 1 1 1 翻转,参照基本变换,定义 f ( n ) f(n) f(n) 为使 n n n 变为 0 0 0 的操作次数,定义 g ( n , p ) g(n,p) g(n,p) 为使 n n n 变为 p p p 位为 1 1 1 其余位为 0 0 0,即 1000 … 1000\dots 1000… 形式的操作次数。对于 f ( n ) f(n) f(n),首先需要将低位转换为 1000 … 1000\dots 1000… 的形式,翻转高位,再将低位转换为 0 0 0;对于 g ( n , p ) g(n,p) g(n,p),若 p p p 位为 1 1 1 那么需要将低位转换为 0 0 0,否则将低位转换为 1000 … 1000\dots 1000… 翻转高位,再将低位转换为 0 0 0。
class Solution
{
public:
int f(int n)
{
if (!n)
{
return 0;
}
int p;
for (int i = 30; i >= 0; i--)
{
if ((n >> i) & 1)
{
p = i;
break;
}
}
return (1 << p) + g(n ^ (1 << p), p - 1);
}
int g(int n, int p)
{
if (p == -1)
{
return 0;
}
if ((n >> p) & 1)
{
return f(n ^ (1 << p));
}
return (1 << p) + g(n, p - 1);
}
int minimumOneBitOperations(int n)
{
return f(n);
}
};