7月算法训练------第十天(位运算)解题报告
题目类型:位运算
题目难度:简单
今天的题前三题比较好做,第四题有点不好想,答案上的思路确实可以,编码的方式我也是第一次见。
第一题、面试题 16.01. 交换数字
- 题目链接:面试题 16.01. 交换数字
- 思路分析:
这一题确实有点简单,直接异或运算,交换两个数的值。 - 代码:
class Solution {
public int[] swapNumbers(int[] numbers) {
numbers[0] = numbers[0] ^ numbers[1];
numbers[1] = numbers[0] ^ numbers[1];
numbers[0] = numbers[0] ^ numbers[1];
return numbers;
}
}
第二题、1342. 将数字变成 0 的操作次数
- 题目链接:1342. 将数字变成 0 的操作次数
- 思路分析:
这一题非常简单,我们可以用基本的四则运算能解,但为了练习位运算,这题还是用位运算来求解:
用(num & 1) == 0
,判断num
是奇数还是偶数,为真则为偶数,为假则为奇数;
用num = num >> 1
,来代替num /= 2
。 - 代码:
class Solution {
public int numberOfSteps(int num) {
int ans = 0;
while(num > 0){
if((num & 1) == 0){
num = num >> 1;
ans++;
}else{
num = num - 1;
ans++;
}
}
return ans;
}
}
第三题、476. 数字的补数
- 题目链接:476. 数字的补数
- 思路分析:
我们运用一个数组存储这个数每一位二进制值,然后将其1变为0,0变为1,再用位运算,将这一数组表示的数计算出来。 - 代码:
class Solution {
public int findComplement(int num) {
int res = 0; // 表示这个num的二进制有几位
int m = num;
while(m > 1){
m = m >> 1;
res++;
}
res++;
m=num;
int[] bir =new int[res];
for(int i = 0; i < res; i++){
if((m & 1) == 0){
bir[i] = 1;
m = m >> 1;
}else{
bir[i] = 0;
m = m >> 1;
}
}
int ans = 0;
for(int i = res - 1; i >= 0; i--){
ans = (ans << 1) + bir[i];
}
return ans;
}
}
第四题、2044. 统计按位或能得到最大值的子集数目
- 题目链接:2044. 统计按位或能得到最大值的子集数目
- 思路分析:
直接枚举所有可能的结果,每种结果都是数组的第i
位取或者不取,对应二进制的0
和1
,然后将取的数进行或运算,得到结果,如果最终值大于最大值,就更新最大值,并将计数值置1
,如果等于最大值,就将计数值加1
。
代码中第一层for循环的1<<nums.length
,表示所有可能的结果的个数,即 2 n − 1 2^n-1 2n−1种结果,这个确实没想到过。
而((i >> j) & 1) == 1
就是判断数组的第(n-j)
位取或不取,这个表示方法确实牛批。 - 代码:
class Solution {
public int countMaxOrSubsets(int[] nums) {
int maxOr = 0, cnt = 0;
for (int i = 0; i < 1 << nums.length; i++) {
int orVal = 0;
for (int j = 0; j < nums.length; j++) {
if (((i >> j) & 1) == 1) {
orVal |= nums[j];
}
}
if (orVal > maxOr) {
maxOr = orVal;
cnt = 1;
} else if (orVal == maxOr) {
cnt++;
}
}
return cnt;
}
}