【英雄算法七月集训】Day10

这篇博客介绍了位运算在解决编程问题中的应用,包括统计最大异或子集数目、交换数组元素、计算数字变为0的操作次数以及找到数字的补数。通过位运算技巧,可以高效地解决这些问题,涉及知识点包括异或、按位或和位移操作。
摘要由CSDN通过智能技术生成

【英雄算法七月集训】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;
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值