题目描述:
给你一个整数 n,你需要重复执行多次下述操作将其转换为 0 :
- 翻转 n 的二进制表示中最右侧位(第 0 位)。
- 如果第 (i-1) 位为 1 且从第 (i-2) 位到第 0 位都为 0,则翻转 n 的二进制表示中的第 i 位。
返回将 n 转换为 0 的最小操作次数。
示例 1:
输入:n = 0
输出:0
示例 2:
输入:n = 3
输出:2
解释:3 的二进制表示为 “11”
“11” -> “01” ,执行的是第 2 种操作,因为第 0 位为 1 。
“01” -> “00” ,执行的是第 1 种操作。
示例 3:
输入:n = 6
输出:4
解释:6 的二进制表示为 “110”.
“110” -> “010” ,执行的是第 2 种操作,因为第 1 位为 1 ,第 0 到 0 位为 0 。
“010” -> “011” ,执行的是第 1 种操作。
“011” -> “001” ,执行的是第 2 种操作,因为第 0 位为 1 。
“001” -> “000” ,执行的是第 1 种操作。
示例 4:
输入:n = 9
输出:14
示例 5:
输入:n = 333
输出:393
- 提示:
0 < = n < = 1 0 9 0 <= n <= 10^9 0<=n<=109
题目链接:1611. 使整数变为 0 的最少操作次数
暴力搜索:
- 思路:每次对两种操作进行搜索,直到整数变为0。有点像这题:[leetcode] LCP 09. 最小跳跃次数(搜索、bfs)都是对可能的状态进行搜索,同样是搜过的状态就不再重复搜。但是本题找不到进一步的优化方法,所以暴力搜索超时>_<
//C++暴搜代码:
const int N=1e9+100;
struct node{
int step;
int x;
};
class Solution {
public:
int minimumOneBitOperations(int n) {
int res;
vector<bool>vis(N,false); //标记某个数是否搜过
queue<node>q;
q.push((node){0,n});
vis[n]=true;
while(!q.empty()){
node now=q.front();
q.pop();
int step=now.step;
int x=now.x;
//cout<<x<<" "<<step<<endl;
if(x==0){res=step;break;}
//搜索“翻转第0位”的情况
if(!vis[x^1]) {
vis[x^1]=true;
q.push((node){step+1,x^1});
}
int p=x&(-x);
p=p<<1;
//搜索“翻转第i位”的情况
if((p^x)&&!vis[p^x]){
vis[p^x]=true;
q.push((node){step+1,p^x});
}
}
return res;
}
};
二进制格雷码转二进制解法:
参考:
leetcode题解
格雷码百度百科
csdn 博客:格雷码与二进制的转换
二进制数与典型格雷码对应关系:
十进制数 | 二进制码 | 典型格雷码 | 十进制数 | 二进制码 | 典型格雷码 |
---|---|---|---|---|---|
0 | 0000 | 0000 | 8 | 1000 | 1100 |
1 | 0001 | 0001 | 9 | 1001 | 1101 |
2 | 0010 | 0011 | 10 | 1010 | 1111 |
3 | 0011 | 0010 | 11 | 1011 | 1110 |
4 | 0100 | 0110 | 12 | 1100 | 1010 |
5 | 0101 | 0111 | 13 | 1101 | 1011 |
6 | 0110 | 0101 | 14 | 1110 | 1001 |
7 | 0111 | 0100 | 15 | 1111 | 1000 |
ac 代码:
class Solution {
public:
int minimumOneBitOperations(int n) {
int res = 0;
while(n!=0)
{
res^=n;
n>>=1;
}
return res;
}
};