[解题报告]《算法零基础100讲》(第44讲) 位运算 (位或) 入门

请添加图片描述

☘前言☘

今天是算法零基础打卡的第44天,题目本身不难,主要是为了理解位运算的。上链接:
《算法零基础100讲》(第44讲) 位运算 (位或) 入门

🧑🏻作者简介:一个从工业设计改行学嵌入式的年轻人
✨联系方式:2201891280(QQ)
全文大约阅读时间: 20min



🎁主要知识点

位或运算

位或运算是计算机内的一个二元运算符,表示为x | y,其真值表如下(可以理解为并联的开关0.0)

xyx | y
000
101
011
111

位或的应用

设置标记位

给定一个数字 将其第五位标记为1。(0b表示二进制数0.0)

   printf("%d\n", x | 0b10000); 

置空标记位

结合上面的标记为的方法,我们先把这位变成1 然后再减去就好了。

   printf("%d\n", (x | a) - a ); 

📓课后习题

1356. 根据数字二进制下 1 的数目排序

1356. 根据数字二进制下 1 的数目排序

给你一个整数数组 arr 。请你将数组中的元素按照其二进制表示中数字 1 的数目升序排序。
如果存在多个数字二进制中 1 的数目相同,则必须将它们按照数值大小升序排列。
请你返回排序后的数组。

解题思路

感觉这道题还是与运算方便些。

int cmp(int *a,int *b){
    int lena = 0,lenb = 0;
    for(int i = 0; i < 32;i++){//统计1 个数
        if((*a)>>i&1)   lena++;
        if((*b)>>i&1)   lenb++;
    }
    if(lena == lenb)    return *a > *b;	//相同按大小排
    return lena > lenb;	//不同1多在后面
}
int* sortByBits(int* arr, int arrSize, int* returnSize){
    qsort(arr,arrSize,sizeof(int),cmp);
    *returnSize = arrSize;
    return arr;
}

231. 2 的幂

231. 2 的幂

给你一个整数 n,请你判断该整数是否是 2 的幂次方。如果是,返回 true ;否则,返回 false 。
如果存在一个整数 x 使得 n == 2x ,则认为 n 是 2 的幂次方。

解题思路

感觉这道题也还是与运算方便些。2333
一行代码解决 仔细看看

bool isPowerOfTwo(int n){
    return n <=0 ? false : !(n &(n-1));
}

2044. 统计按位或能得到最大值的子集数目

2044. 统计按位或能得到最大值的子集数目

给你一个整数数组 nums ,请你找出 nums 子集 按位或 可能得到的 最大值 ,并返回按位或能得到最大值的 不同非空子集的数目
如果数组 a可以由数组b 删除一些元素(或不删除)得到,则认为数组 a是数组b 的一个 子集 。如果选中的元素下标位置不一样,则认为两个子集 不同
对数组 a 执行 按位或 ,结果等于 a[0] OR a[1] OR … OR a[a.length - 1](下标从 0 开始)。

解题思路1

我总觉得暴力过不了 ,但是还是试了试。

  1. 我们应该明白越多数按位或结果会越来越大,所以最大值一定是数组内的所有值位或
  2. 表示子集的方式可以用二进制来表示 二进制的0和1表示对应元素有还是没有,遍历所有子数组就是从1 到
    2 n u m s S i z e − 1 2^{numsSize - 1} 2numsSize1
    来进行表示的
int countMaxOrSubsets(int* nums, int numsSize){
    int temp = 0,ans = 0;
    for(int i = 0;i < numsSize;i++)	//找出最大值
        temp |= nums[i];
    for(int i = 0;i < 1 << numsSize;i++){//遍历所有子集
        int tempans = 0;
        for(int j = 0; j < numsSize;j++){
            if(i & (1 << j))    tempans |= nums[j];
        }
        if(tempans == temp) ans++;
    }
    return ans;
}

结果1
能过,对,没错 仅仅是能过-.-109ms 可怕0.0

解题思路2

上面的方法有个很大的问题就是造成了很大的重复计算,比如计算{1,2,3,4} 和{1,2,3}这两个子集的时候。第一个的结果就是第二个的结果再与4或就好了?
我们能思考的就是空间换时间,将所有子集的或的结果保存下来。然后计算新子集的时候运用之前的结果。

  1. 初始条件是将所有元素插入到的对应的位置。
  2. 然后我们知道i-i的特点从低到高的第一个1之前的元素是完全相同的,我们可以利用这个特性来判断是否是只有一个元素,用于跳过
    3.当不是只有一个元素的时候 我们可以用低位的结果和高位的结果相与来得到最终的结果。高位的元素一定比当前的元素小所以也进行过了计算。
int countMaxOrSubsets(int* nums, int numsSize){
    int temp = 0,ans = 0,n = 1 <<numsSize;
    int hash[1 << numsSize];
    for(int i = 0;i < numsSize;++i)
        hash[1<<i] = nums[i];//插入位置元素
    for(int i = 1;i < n;++i){
        int lowBit = i & (-i);
        if((i ^ lowBit) == 0) continue;//只有一个元素已经插入
        hash[i] = hash[i ^ lowBit] | hash[lowBit];//状态转移方程
    }
    for(int i = 0;i < n;i++)
        if(hash[i] == hash[n -1])    ans++;//统计
    return ans;
}

结果2

8ms0.0 哇 太强了


📑写在最后

我现在可以开始写时间管理的文章了,不晓得有没有人看,并且我只有一个小时,等下还是要去图书馆进行复习的0.0

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

XingleiGao

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值