[位运算] 剑指 Offer II 005. 单词长度的最大乘积

100 阅读1分钟

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

每日刷题 2022.08.24

题目

  • 给定一个字符串数组 words,请计算当两个字符串 words[i]words[j] 不包含相同字符时,它们长度的乘积的最大值。假设字符串中只包含英语的小写字母。如果没有不包含相同字符的一对字符串,返回 0o。

示例

  • 示例1
输入: words = ["abcw","baz","foo","bar","fxyz","abcdef"]
输出: 16 
解释: 这两个单词为 "abcw", "fxyz"。它们不包含相同字符,且长度的乘积最大。
  • 示例2
输入: words = ["a","ab","abc","d","cd","bcd","abcd"]
输出: 4 
解释: 这两个单词为 "ab", "cd"
  • 示例3
输入: words = ["a","aa","aaa","aaaa"]
输出: 0 
解释: 不存在这样的两个单词。

提示

  • 2 <= words.length <= 1000
  • 1 <= words[i].length <= 1000
  • words[i] 仅包含小写字母

解题思路

  • 容易想到的做法,将所有的字符串两两进行比较(字符串中的每一个字符进行比较,可以使用indexOf()函数),如果两个字符串不存在相同的元素,那么就计算两个字符串长度的乘积,最终取乘积的最大值即可。
  • 分析时间复杂度:o(n ^ 3),因为n = 10 ^ 3,那么显然是会超时的,没有办法通过题目。

位运算

  • 根据题意可知:字符串中只包含小写字母,也就是只有26个小写字母。
  • 一个整数使用二进制表示是32位,那么通过将小写字母转换成二进制中的一位来表示,因此当两个字符串的二进制,按位与结果等于0,那么就表示这两个字符串不存在相同的字母,就可以计算两个字符串长的的乘积,最后将所有的乘积取一个最大值,返回即可。
  • 时间复杂度:o(n^2)

AC代码

var maxProduct = function(words) {
  // 不存在相同的字符,每一个都需要比较的话,就会超时
  // 使用位运算优化,可以提前处理位运算的值,将时间复杂度将为o(n * n + m * n)
  // 如果层数过多的,可能会超时的,可以分析其是否能够将其拆分
  let n = words.length, bitmask = new Array(n).fill(0).map(() => new Array(26).fill(0));
  let a = 'a'.charCodeAt();
  for(let i = 0; i < n; i++) {
    let cur = 0;
    for(let one of words[i]) {
      let bit = one.charCodeAt() - a;
      cur |= (1 << bit);
    }
    bitmask[i] = cur;
  }
  // console.log(bitmask)
  // 26个字母中如果有1,表示当前这一位出现过
  let ans = 0;
  for (let i = 0; i < n; i++) {
    for(let j = i + 1; j < n; j++) {
      // 两两进行比较,按位与
      if((bitmask[i] & bitmask[j]) === 0) {
        // 不存在相同的字符
        ans = Math.max(words[i].length * words[j].length, ans);
      }
    }
  }
  return ans;
};