一起刷LeetCode——最大单词长度乘积(位运算)

45 阅读1分钟

携手创作,共同成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第22天,点击查看活动详情

最大单词长度乘积

给你一个字符串数组 words ,找出并返回 length(words[i]) * length(words[j]) 的最大值,并且这两个单词不含有公共字母。如果不存在这样的两个单词,返回 0 。

分析

  • 给到一个字符串数组,要找到没有公共字母的两个最长单词长度的乘积,可以直接暴力解决

暴力

  • 双重遍历这个数组,使用一个变量来维护长度的乘积的最大值,查看当前第i个和第j个有没有公共字母,如果没有公共字母就更新乘积
  • 描述起来比较简单,因此代码也不是很复杂

代码

const compare = (a, b) => {
  for (let i = 0; i < a.length; i++){
    if ( b.includes(a[i]) ){
       return false;
    }
  } 
  return true;
};

const maxProduct = function(words) {
  let max = 0;
  for (let i = 0; i < words.length - 1; i++) {
    for (let j = i + 1; j < words.length; j++) {
      const a = words[i];
      const b = words[j];
      let unique = true;
      if ( compare(words[i], words[j]) ) {
        max = Math.max( max, (words[i].length * words[j].length) )
      }
    }
  }

  return max;
};  
  • 但是暴力解决看上去过于暴力了,这道题怎么着也是中等难度,尊重一下这道题的难度,进行一下优化,要判断是否有相同的字母,对于判断某个位置是否相同,好像可以使用位运算

位运算

  • 每个字母都有其ASCII码,所以把每个位置上的字母转换成位掩码,通过按位与,只要有一个为0,就是0,如果相同就是1
  • 生成位掩码:定义每个字符对应的数字,a-z分别为0-25,单词的每个字符对应的数字c就是生成二进制码的位数,每个字符生成的二进制通过或运算得到一个单词对应的位掩码
  • 所以就可以把字符串的比较转为位掩码的按位与运算,可以在拿到数组的时候全部转为位掩码后计算长度的最大乘积

代码

const convertToInt = str => {
  let int = 0
  const baseCharCode = ('a').charCodeAt(0)
  for (let i = 0; i < str.length; i++) {
    int |= 1 << (str.charCodeAt(i) - baseCharCode)
  }
  return int
}

const compare = (a, b) => {
  if ((a & b) === 0) return true
  else return false
}

const maxProduct = function(words) {
  const ints = words.map(word => convertToInt(word))
  let max = 0
  for (let i = 0; i < ints.length - 1; i++) {
    for (let j = i + 1; j < ints.length; j++) {
      if ( compare(ints[i], ints[j]) ) {
        max = Math.max( max, (words[i].length * words[j].length) )
      }
      
    }
  }
  return max
};

总结

  • 位运算总是用在不经意间,出现在前端的概率较低,但是对于按位比较异同的敏感度还是要有的,毕竟JavaScript支持位运算
  • 今天也是有收获的一天