【万人千题】算法按位或进阶12.4总结报告

一:知识点

初阶的总结在前一篇文章已经写过,如果不太理解,可以去看看:

【万人千题】算法按位或12.3总结_C_Ryson的博客-CSDN博客

进阶的我们来讲一讲应用的方法。

在初阶中,我们讲到按位或可以处理一个数的某一位。那么这个特性也可以用在计数上,用这个位上的0,1来表示是否有存在。比如用在字符串上,如:用一个int型数前26位来表示一个字符串中是否出现过a~z的字母,将字符串的状态压缩成一个数字,这样就好比较两个字符串是否完全不同。

ps:说到计数,这时候大家可能会想起打表,类似哈希表一样,遍历整个字符串,然后记下来,这未尝不是一种方法。今天我们就不讨论。(小声:其实我对于这个我只想到二维数组的比较,可能更麻烦。)

那么问题来了,如何将字符串中的元素压缩到一个数中?

我们用一个数字来表示一个字符串的状态。我们知道按位或运算的话或上一个真值就会是真,只有两个都是假的时候才会是假。而字符串在内存中又是以ASCII码值计算。将其减去‘a’,就可以得到0~25的数字,再让1<<相同数,就可以将一个数低26位上的数字改变,那么这样就可以改变一个位数的数字而不会去影响其他位。得到这个之后再进行&操作,如果两个字符串完全没有相同元素,那么他们低26位上就一定不会出现两个位上都是1的情况,也就是一定是0,如果不是0说明两个数有相同的元素。这样就可以将状态压缩。

二:习题

318. 最大单词长度乘积 - 力扣(LeetCode) (leetcode-cn.com)

剑指 Offer II 005. 单词长度的最大乘积 - 力扣(LeetCode) (leetcode-cn.com)

这两题一样就放一起了,说一下两种解法。

int maxProduct(char ** words, int wordsSize)
{
    int i,j;
    int ans=0;
       for(i=0;i<wordsSize;i++)
       {
           for(j=i+1;j<wordsSize;j++)
           {
               if(strpbrk(words[i],words[j])==NULL)
                 ans=fmax(ans,strlen(words[i])*strlen(words[j]));
           }
       }
       return ans;
}

 这个解法是使用库函数strbprk,这个函数可以帮我们寻找两个字符串是否有相同的字符,如果找不到返回NULL空指针,所以我们可以直接用这个判定一下。然后再用fmax,这个函数会返回两者中的较大值,将ans与符合条件的两个字符串的长度的乘积比较一下,看看谁更大ans就是谁。然后就用两个循环遍历数组即可。

int maxProduct(char ** words, int wordsSize)
{
     int arr[wordsSize];
     int i=0;
     int ans=0;
     for(i=0;i<wordsSize;i++)
     {
         arr[i]=0;
     }
     for(i=0;i<wordsSize;i++)
     {
          int j=0;
          while(words[i][j]!='\0')
          {
              arr[i]|=(1<<(words[i][j]-'a'));
              j++;
          }
          printf("%d ",arr[i]);
     }
     for(i=0;i<wordsSize;i++)
     {
         int j=i+1;
         for(;j<wordsSize;j++)
         {
             if((arr[i]&arr[j])==0)
              {
                 int tmp= strlen(words[i])*strlen(words[j]);
                 if(tmp>ans)
                   ans=tmp;
              }
         }

     }
     return ans;
}

第二中方法就是上述提及的方法,我们开一个数组arr,将每个words中的字符串状态压缩到arr中,减去一个偏移量‘a’,用int类型低26位二进制位来模拟字符串的状态,就可以知道那些字符在字符串中出现过。在判断阶段的时候将要比较的两个字符串对应的arr中的值按位与就可以知道状态了。就可以知道两个字符串是否符合条件。

1318. 或运算的最小翻转次数 - 力扣(LeetCode) (leetcode-cn.com)

int minFlips(int a, int b, int c)
{
    int i=0;
    int count=0;
    for(i=0;i<31;i++)
    {
        int tmpa=(a>>i)%2;
        int tmpb=(b>>i)%2;
        int tmpc=(c>>i)%2;
        printf("%d ",tmpc);
        if((tmpa|tmpb)==tmpc)
        continue;
        else 
        {
            if((tmpa==tmpb)&&tmpa==1)
            count+=2;
            else
            count+=1;
        }
    }
    return count;
}

​​​​​ 这道题的解释在《算法零基础100讲》(第45讲) 位运算 (位或) 进阶_英雄哪里出来-CSDN博客​​​​​​

已经很清楚啦,大家可以去看看。

三:小总结

算法很难,但是做出题来和有点理解之后却也是快乐的。感谢各位看到这里,我们一起再进步吧。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值