[解题报告]《算法零基础100讲》(第45讲) 位运算 (位或) 进阶

请添加图片描述

☘前言☘

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

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



🎁主要知识点

位或运算的运用

给你三个正整数 a、b 和 c。
你可以对 a 和 b 的二进制表示进行位翻转操作,返回能够使按位或运算 a OR b == c 成立的最小翻转次数。
「位翻转操作」是指将一个数的二进制表示任何单个位上的 1 变成 0 或者 0 变成 1 。
在这里插入图片描述

abc最小反转次数操作方式
0000无需翻转
0011a变1(或者b变1)
0101b变0
0110无需翻转

好了 真值表我不弄完了 ,其实可以看到

  • 假如直接满足就是0次
  • 假如c是0 需要把a和b都变成0 需要的就是a+b的值
  • 假如c是1 需要把a和b都变成1 需要的就是 一次 因为只要有一个1就好了
int getbit(int v, int i) {
   return (v & (1<<i)) ? 1 : 0;    //  取出第i位
}

int minFlips(int a, int b, int c){
   int i;
   int ans = 0;
   int ai, bi, ci;
   for(i = 0; i < 31; ++i) {
       ai = getbit(a, i);
       bi = getbit(b, i);
       ci = getbit(c, i);
       if( (ai | bi) == ci ) {     // 直接满足无需翻转
           continue;
       }else if(ci == 0) {
           ans += (ai + bi);       // 需要将a和b都变成0
       }else if(ci == 1) {
           ans += 1;               // 只需要把一个变成1就好了
       }
   }
   return ans;
}


📓课后习题

318. 最大单词长度乘积

318. 最大单词长度乘积

给定一个字符串数组 words,找到 length(word[i]) * length(word[j]) 的最大值,并且这两个单词不含有公共字母。你可以认为每个单词只包含小写字母。如果不存在这样的两个单词,返回 0。

解题思路

这道题比较综合,我的做法是将所有的单词用了一个26位的数字进行记录。然后用与操作进行判断是否交叉。

typedef struct {	//定义结构体
    int len;
    int bit;
}def;
void setdef(char *s,def * a){	//拿到位的hash表 同时顺带拿到长度
    int ans = 0,i = 0;
    for(i = 0;s[i];i++)
        ans |= (1 << (s[i] - 'a'));//对应位置1
    a->bit = ans;
    a->len = i;
}
int maxProduct(char ** words, int wordsSize){
    def hash[wordsSize];
    int ans= 0;
    for(int i = 0;i < wordsSize;i++)	//拿到每个元素的长度和位hash
        setdef(words[i],&hash[i]);
    int max =0;
    for(int i = wordsSize - 1;i >=0 ;i--)
        for(int j = i - 1;j >= 0;j--)	//遍历
            if((hash[i].bit & hash[j].bit) == 0)	//如果没重叠
                if(hash[i].len*hash[j].len > max) max = hash[i].len*hash[j].len;	//更新最大值
    return max;
}

1318. 或运算的最小翻转次数

1318. 或运算的最小翻转次数

给定一个字符串数组 words,找到 length(word[i]) * length(word[j]) 的最大值,并且这两个单词不含有公共字母。你可以认为每个单词只包含小写字母。如果不存在这样的两个单词,返回 0。

解题思路

看上面那道题0.0


1318. 或运算的最小翻转次数

1318. 或运算的最小翻转次数

给你三个正整数 a、b 和 c。
你可以对 a 和 b 的二进制表示进行位翻转操作,返回能够使按位或运算 a OR b == c 成立的最小翻转次数。
「位翻转操作」是指将一个数的二进制表示任何单个位上的 1 变成 0 或者 0 变成 1 。
在这里插入图片描述

解题思路

看最上面的知识点0.0

int getbit(int v, int i) {
    return (v & (1<<i)) ? 1 : 0;    
}

int minFlips(int a, int b, int c){
    int i;
    int ans = 0;
    int ai, bi, ci;
    for(i = 0; i < 31; ++i) {
        ai = getbit(a, i);
        bi = getbit(b, i);
        ci = getbit(c, i);
        if( (ai | bi) == ci ) {    
            continue;
        }else if(ci == 0) {
            ans += (ai + bi);       // 需要全变成0
        }else if(ci == 1) {
            ans += 1;              
        }
    }
    return ans;
}


898. 子数组按位或操作

898. 子数组按位或操作

我们有一个非负整数数组 A。
对于每个(连续的)子数组 B = [A[i], A[i+1], …, A[j]] ( i <= j),我们对 B 中的每个元素进行按位或操作,获得结果 A[i] | A[i+1] | … | A[j]。
返回可能结果的数量。 (多次出现的结果在最终答案中仅计算一次。)

解题思路

我们知道,或操作是单调并不减的,所以可能或的最大值就是把数组所有元素进行或。所以一开始可以设定max值。

  • 扫描连续子集的适合到达最小值就可以跳出。
  • 利用hash表来存储已经扫描过的值防止重复计算。

有几个重要的点:

  1. hash表一定要用bool类型 因为省空间 233
  2. hash表不能全部初始化,会超时0.0
bool hash[1100000001];
int subarrayBitwiseORs(int* arr, int arrSize){
    int max = 0,ans = 0;
    for(int i = 0;i < arrSize;i++)
        max |= arr[i];  //算出最大的或值
    for(int i = 0;i < arrSize;i++){	//初始化hash表
        int temp = 0;
        for(int j = i;j < arrSize;j++){
            temp |= arr[j];
            hash[temp] = 0;
            if(temp == max) break;
        }
    }
    hash[max] = 1,ans++;
    for(int i = 0;i < arrSize;i++){	//统计
        int temp = 0;
        for(int j = i;j < arrSize;j++){
            temp |= arr[j];
            if(!hash[temp])    ans++,hash[temp] = 1;
            if(temp == max) break;
        }
    }
    return ans;
}

yyds0.0
在这里插入图片描述


📑写在最后

今天的题有点意思,233,我继续去分布式了复习了,主要是要完成bt客户端,好难啊-.-

  • 4
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

XingleiGao

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

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

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

打赏作者

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

抵扣说明:

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

余额充值