【英雄算法七月集训】Day10
本日关键字
位运算
2044. 统计按位或能得到最大值的子集数目
//1 第一个for循环,假设数组有2个元素,那么子集数量将为
(2^n-1)
个,此处则为2^2-1
,3个,那么我们则这样枚举数组下标从0开始
i = 0->00 //表示不选任何元素
i = 1->01 // 表示选取第0个元素
i = 2->10 //表示选取第1个元素
i = 3->11 //表示选取第0个和第1个元素
然后里面的for循环,对每一位假设选和不选 (有第一层for循环决定),假设数组有两个元素,那么两位bit 表示该数 选与不选,
判断是否
(i>>j)&1==1
如
当 j=0 则右移0位,此位在
i = 0->00
表示不选任何元素则不累加
当j=1 则右移1位,此位在
i=1->10
,二进制表示为i=1 01
j=0
i >> j 01
1 -> 01
最后==1 则表示选取这个第0个的元素,则累加。累加代码
ans |= nums[j]
j=1
i >> j 10
1 -> 01
最后!=1 则表示不选取此元素,则不累加
j循环结束时,可计算出一个数组异或的值,然后和此时的maxv进行比较,若大于maxv,则将此时置为maxv,并且结果计数器ans置为1
如果等于maxv则计数器ans++;
最后返回结果
位运算
class Solution {
public int countMaxOrSubsets(int[] nums) {
int n = nums.length;
int maxv = -1,maxc = 0;
int i,j;
for(i=0;i<(1<<n);i++){ //1
int ans = 0;
for(j=0;j<n;j++){
//i 0 j 0 0000
// 0001
// 0001
if(((i>>j)&1)==1){
// 3->0011
// 0->0000
// 0011
//
ans |= nums[j];
}
}
if(ans>maxv){
maxv=ans;
maxc=1;
}else if(ans==maxv){
++maxc;
}
}
return maxc;
}
}
面试题 16.01. 交换数字
class Solution {
public void swap(int[] a){
//a[0]为1 ->0001 a[1]为2->0010
// 0001
// 0010
// 0011 -> 3 = a[0]
a[0] = a[0] ^ a[1];
// a[0]为3 ->0011 a[1]为2->0010
// 0011
// 0010
// 0001 -> 1 = a[1]
a[1] = a[0] ^ a[1];
// a[0]为3 ->0011 a[1]为1->0001
// 0011
// 0001
// 0010 -> 1 = a[0] =2 交换了
a[0] = a[0] ^ a[1];
}
public int[] swapNumbers(int[] numbers) {
swap(numbers);
return numbers;
}
}
1342. 将数字变成 0 的操作次数
class Solution {
public int numberOfSteps(int num) {
if(num==0){
return 0;
}
if((num&1) == 0){
return numberOfSteps(num/2)+1;
}
return numberOfSteps(num-1)+1;
}
}
476. 数字的补数
解法一
找到比num大的第一个K
然后num和k-1 做异或操作
比如num 为 3 二进制 0011 比num大的第一个k 0100 k-1 0011 num ^(k-1) 0011 ^ 0011 —>1100
class Solution {
public int findComplement(int num) {
long k=1;
while(k <= num){
k<<=1;
}
return (int)(num ^(k-1));
}
}
解法二
代码很简洁 但是不去动手写写 有点不好理解
模拟(lowbit)
class Solution {
public int findComplement(int num) {
int x = 0;
for (int i = num; i != 0; i -= i & -i) x = i;
return ~num & (x - 1);
}
}
解法三
模拟(遍历)
class Solution {
public int findComplement(int num) {
int s = -1;
for (int i = 31; i >= 0; i--) {
if (((num >> i) & 1) != 0) {
s = i;
break;
}
}
int ans = 0;
for (int i = 0; i < s; i++) {
if (((num >> i) & 1) == 0) ans |= (1 << i);
}
return ans;
}
}