「这是我参与11月更文挑战的第14天,活动详情查看:2021最后一次更文挑战」
题目
给定一个字符串数组 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();
在增加单词中每个字符串与另一个单词所有字符串对比,时间复杂度将远超出题目要求;
所以,必须优化此思路。
如何优化呢??
上述思路中,找到数组中两个单词不含有公共字母必然要用到单词逐一比较,所以此处已经没有优化空间,
只能从对比两个单词是否有公共字母这点优化,所以这个问题就转变为如何判断两个单词是否含有公共字母?
如何判断两个单词是否含有公共字母?
//假如有单词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
}