☘前言☘
今天是算法零基础打卡的第45天,题目本身不难,主要是为了理解位运算的。上链接:
《算法零基础100讲》(第45讲) 位运算 (位或) 进阶
🧑🏻作者简介:一个从工业设计改行学嵌入式的年轻人
✨联系方式:2201891280(QQ)
⏳全文大约阅读时间: 20min
🎁主要知识点
位或运算的运用
给你三个正整数 a、b 和 c。
你可以对 a 和 b 的二进制表示进行位翻转操作,返回能够使按位或运算 a OR b == c 成立的最小翻转次数。
「位翻转操作」是指将一个数的二进制表示任何单个位上的 1 变成 0 或者 0 变成 1 。
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. 最大单词长度乘积
给定一个字符串数组
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. 或运算的最小翻转次数
给定一个字符串数组
words
,找到length(word[i]) * length(word[j])
的最大值,并且这两个单词不含有公共字母。你可以认为每个单词只包含小写字母。如果不存在这样的两个单词,返回 0。
解题思路
看上面那道题0.0
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. 子数组按位或操作
我们有一个非负整数数组 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;
}
yyds0.0
📑写在最后
今天的题有点意思,233,我继续去分布式了复习了,主要是要完成bt客户端,好难啊-.-