[路飞]_夜查最大单词长度乘积

641 阅读3分钟

「这是我参与11月更文挑战的第14天,活动详情查看:2021最后一次更文挑战

318. 最大单词长度乘积

题目

给定一个字符串数组 words,
找到 length(word[i]) * length(word[j]) 的最大值。
并且这两个单词不含有公共字母。
你可以认为每个单词只包含小写字母。如果不存在这样的两个单词,返回 0

示例1:

输入: ["abcw","baz","foo","bar","xtfn","abcdef"]
输出: 16 
解释: 这两个单词为 "abcw", "xtfn"

示例2

输入: ["a","ab","abc","d","cd","bcd","abcd"]
输出: 4 
解释: 这两个单词为 "ab", "cd"

目标: 找到数组中两个单词不含有公共字母;

对比两个单词不含有公共字母可以将两个单词中字符串逐一比较;
但是word[i]与word[j]单词比较时间复杂度已经达到O(n2n^2);

在增加单词中每个字符串与另一个单词所有字符串对比,时间复杂度将远超出题目要求;

所以,必须优化此思路。

如何优化呢??

上述思路中,找到数组中两个单词不含有公共字母必然要用到单词逐一比较,所以此处已经没有优化空间,

只能从对比两个单词是否有公共字母这点优化,所以这个问题就转变为如何判断两个单词是否含有公共字母?

如何判断两个单词是否含有公共字母?

//假如有单词s1 = 'ace' s2 = 'bdf'
// 处理逐一对比字母,还有什么方法能判断两个单词是否含有公共字符串呢?
// 可以这样处理
// 将单词中字母用数字代替;因为单词无论有多少字母,字母都在a-z之间;
// 哪s1 = 'ace' 是不是可以转换为 '10101'
// 怎么转换的呢?
// a是26个字母第1个字母,b是第2个,c是第3个......
// 将单词转化为26位二进制,如果单词出现a在单词二进制表达中将第一位设置为1
// 所以,s1 = 'ace' = '101010'
// 所以,s2 = 'bdf' = '010101'
// 这规律不久出来了,s1与s2的二进制表达形式逐位相与,得到0即可确认两单词没有公共字符串,是不是
// 了解了这个,优化点不就来了

根据上述思路编辑代码如下:

var maxProduct = function (words) {
// 获取单词数量
  const len = words.length
  let list = Array(len).fill(0)
  for (let i = 0; i < len; i++) {
  // 遍历单词
    const s = words[i]
    for (let j = 0; j < s.length; j++) {
    // 将该处单词的字符串转化为二进制
      list[i] |= 1 << (s[j].charCodeAt() - 'a'.charCodeAt())
    }
  }

  let result = 0
  for (let i = 0; i < len; i++) {
    for (let j = i + 1; j < len; j++) {
    
    // 如果两个单词二进制逐位相与,表示两个单词没有公共字母,取乘积,寻最大值
      if ((list[i] & list[j]) == 0) {
        result = Math.max(result, words[i].length * words[j].length)
      }
    }
  }
  
  // 输出结果
  return result
}