❓ 题目一
693. 交替位二进制数
难度:简单
给定一个正整数,检查它的二进制表示是否总是 0、1 交替出现:换句话说,就是二进制表示中相邻两位的数字永不相同。
示例 1:
输入:n = 5
输出:true
解释:5 的二进制表示是:101
示例 2:
输入:n = 7
输出:false
解释:7 的二进制表示是:111.
示例 3:
输入:n = 11
输出:false
解释:11 的二进制表示是:1011.
提示:
- 1 < = n < = 2 31 − 1 1 <= n <= 2^{31} - 1 1<=n<=231−1
💡思路:
基础知识必知:一篇文章搞懂位运算
法一:数学
- 将
n
转换成二进制以10
结尾的数; - 然后使用数学除法,除以
4
,判断余数的二进制是否为10
(对应的十进制为2
),如果不是,则不是交替位二进制数,返回false
。
法二:位运算
对于
1010
这种位级表示的数,把它向右移动1
位得到101
,这两个数每个位都不同,因此异或得到的结果为1111
。
-
对输入
n
的二进制表示右移一位后,得到的数字再与n
按位异或得到a
。- 当且仅当输入
n
为交替位二进制数时,a
的二进制表示全为111
(不包括前导000
)。
- 当且仅当输入
-
将
a
与a+1
按位与,当且仅当a
的二进制表示全为1
时,结果为0
。
结合上述两步,可以判断输入是否为交替位二进制数。
🍁代码:(Java、C++)
法一:数学
Java
class Solution {
public boolean hasAlternatingBits(int n) {
if((n & (-n)) == 1) n >>= 1;
while(n > 0){
if(n % 4 != 2) return false;
n /= 4;
}
return true;
}
}
C++
class Solution {
public:
bool hasAlternatingBits(int n) {
if((n & (-n)) == 1) n >>= 1;
while(n > 0){
if(n % 4 != 2) return false;
n /= 4;
}
return true;
}
};
法二:位运算
Java
class Solution {
public boolean hasAlternatingBits(int n) {
int a = (n ^ (n >>> 1));
return (a & (a + 1)) == 0;
}
}
C++
class Solution {
public:
bool hasAlternatingBits(int n) {
long a = (n ^ (n >> 1));
return (a & (a + 1)) == 0;
}
};
🚀 运行结果:
🕔 复杂度分析:
- 时间复杂度: O ( 1 ) O(1) O(1),仅使用了常数时间来计算。
- 空间复杂度: O ( 1 ) O(1) O(1),使用了常数空间来存储中间变量。
题目来源:力扣。
❓ 题目二
476. 数字的补数
难度:简单
对整数的二进制表示取反(0
变 1
,1
变 0
)后,再转换为十进制表示,可以得到这个整数的补数。
- 例如,整数
5
的二进制表示是"101"
,取反后得到"010"
,再转回十进制表示得到补数2
。
给你一个整数 num
,输出它的补数。
示例 1:
输入:num = 5
输出:2
解释:5 的二进制表示为 101(没有前导零位),其补数为 010。所以你需要输出 2 。
示例 2:
输入:num = 1
输出:0
解释:1 的二进制表示为 1(没有前导零位),其补数为 0。所以你需要输出 0 。
提示:
- 1 < = n u m < 2 31 1 <= num < 2^{31} 1<=num<231
注意:本题与 1009. 十进制整数的反码 相同。
💡思路:
基础知识必知:一篇文章搞懂位运算
法一:数学
- 使用数学乘除法。
法二:补码的性质
- 补码和原码相加等于
2
n
−
1
2^n - 1
2n−1,其中
n
是num
转换成二进制的位数。
法三:位运算异或
- 对于
00000101
,要求补码可以将它与00000111
进行异或操作。 - 那么问题就转换为求掩码
00000111
。
🍁代码:(Java、C++)
法一:数学
Java
class Solution {
public int findComplement(int num) {
int ans = 0;
int i = 0;
while(num > 0){
ans += (num & 1) == 0 ? Math.pow(2, i) : 0;
i++;
num /= 2;
}
return ans;
}
}
C++
class Solution {
public:
int findComplement(int num) {
int ans = 0;
int i = 0;
while(num > 0){
ans += (num & 1) == 0 ? pow(2, i) : 0;
i++;
num /= 2;
}
return ans;
}
};
法二:补码的性质
Java
class Solution {
public int findComplement(int num) {
if(num >= Integer.MAX_VALUE / 2) return Integer.MAX_VALUE - num;
int tmp = 1;
while(tmp <= num){
tmp *= 2;
}
return tmp - 1 - num;
}
}
C++
class Solution {
public:
int findComplement(int num) {
if(num >= INT_MAX / 2) return INT_MAX - num;
int tmp = 1;
while(tmp <= num){
tmp *= 2;
}
return tmp - 1 - num;
}
};
法三:位运算异或
Java
class Solution {
public int findComplement(int num) {
int mask = num;
mask |= mask >> 1;
mask |= mask >> 2;
mask |= mask >> 4;
mask |= mask >> 8;
mask |= mask >> 16;
return (mask ^ num);
}
}
C++
class Solution {
public:
int findComplement(int num) {
int mask = num;
mask |= mask >> 1;
mask |= mask >> 2;
mask |= mask >> 4;
mask |= mask >> 8;
mask |= mask >> 16;
return (mask ^ num);
}
};
🚀 运行结果:
🕔 复杂度分析:
-
时间复杂度: O ( l o g n u m ) O(log num) O(lognum),找出
num
二进制表示最高位的1
需要的时间为 O ( l o g n u m ) O(log num) O(lognum), 法三为 O ( 1 ) O(1) O(1)。 -
空间复杂度: O ( 1 ) O(1) O(1)。
题目来源:力扣。
放弃一件事很容易,每天能坚持一件事一定很酷,一起每日一题吧!
关注我 leetCode专栏,每日更新!