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

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

☘前言☘

今天是算法零基础打卡的第45天,题目本身不难,主要是为了理解位运算的。上链接:

《算法零基础100讲》(第45讲) 位运算 (位或) 进阶


🧑🏻作者简介:一个从工业设计改行学嵌入式的年轻人

✨联系方式:2201891280(QQ)

⏳全文大约阅读时间: 20min


全文目录

 ☘前言☘

 🎁主要知识点

            位或运算的运用

 📓课后习题

            318. 最大单词长度乘积

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

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

            898. 子数组按位或操作

 📑写在最后

🎁主要知识点

位或运算的运用

给你三个正整数 a、b 和 c。

你可以对 a 和 b 的二进制表示进行位翻转操作,返回能够使按位或运算 a OR b == c 成立的最小翻转次数。

「位翻转操作」是指将一个数的二进制表示任何单个位上的 1 变成 0 或者 0 变成 1 。

bd71824a39c81cf3cf6ba89c1194ee2.png

a b c 最小反转次数         操作方式

0 0 0         0                无需翻转

0 0 1         1             a变1(或者b变1)

0 1 0         1                 b变0

0 1 1         0                 无需翻转

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


假如直接满足就是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 。

fc63bfc6973e0d187ed8b162d600ac1.png


解题思路


看最上面的知识点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表来存储已经扫描过的值防止重复计算。

有几个重要的点:


hash表一定要用bool类型 因为省空间 233

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;
}


相关文章
|
3月前
|
算法 数据处理 C语言
C语言中的位运算技巧,涵盖基本概念、应用场景、实用技巧及示例代码,并讨论了位运算的性能优势及其与其他数据结构和算法的结合
本文深入解析了C语言中的位运算技巧,涵盖基本概念、应用场景、实用技巧及示例代码,并讨论了位运算的性能优势及其与其他数据结构和算法的结合,旨在帮助读者掌握这一高效的数据处理方法。
91 1
|
2月前
|
算法
【算法】位运算合集
/鸽巢原理优化//位图原理//bitMap&0001000只有非0或者0两个结果//说明当前bitMap位是0,那就添加进去}else{//1:把字符串转化为字符数组// //2:把字符扔到hash表中// //获取hash表中x的value值// }else{// }// }
|
6月前
|
算法
【算法】位运算算法——消失的两个数字(困难)
【算法】位运算算法——消失的两个数字(困难)
|
6月前
|
算法
【算法】位运算算法——只出现一次的数字Ⅱ
【算法】位运算算法——只出现一次的数字Ⅱ
|
6月前
|
算法
【算法】位运算算法——判断字符是否唯一
【算法】位运算算法——判断字符是否唯一
|
8月前
|
机器学习/深度学习 搜索推荐 算法
【再识C进阶2(下)】详细介绍指针的进阶——利用冒泡排序算法模拟实现qsort函数,以及一下习题和指针笔试题
【再识C进阶2(下)】详细介绍指针的进阶——利用冒泡排序算法模拟实现qsort函数,以及一下习题和指针笔试题
|
4月前
|
算法 Java 程序员
【算法每日一练及解题思路】有n级台阶,一次只能上1级或2级,共有多少种走法?
本文深入解析了“爬楼梯问题”,探讨了递归与迭代两种解法,并提供了Java代码实现。通过分析问题本质,帮助读者理解动态规划技巧,提高解决实际编程问题的能力。关键词:Java, 算法, 动态规划, 爬楼梯问题, 递归, 迭代。
168 0
|
4月前
|
算法 C++
【算法解题思想】动态规划+深度优先搜索(C/C++)
【算法解题思想】动态规划+深度优先搜索(C/C++)
|
6月前
|
算法
【算法】位运算算法——两整数之和
【算法】位运算算法——两整数之和
|
6月前
|
算法
【算法】位运算算法——丢失的数字
【算法】位运算算法——丢失的数字