「这是我参与2022首次更文挑战的第17天,活动详情查看:2022首次更文挑战」
题目
318. 最大单词长度乘积
给你一个字符串数组 words ,找出并返回 length(words[i]) * length(words[j]) 的最大值,并且这两个单词不含有公共字母。如果不存在这样的两个单词,返回 0 。
示例 1:
输入:words = ["abcw","baz","foo","bar","xtfn","abcdef"]
输出:16
解释:这两个单词为 "abcw", "xtfn"。
示例 2:
输入:words = ["a","ab","abc","d","cd","bcd","abcd"]
输出:4
解释:这两个单词为 "ab", "cd"。
示例 3:
输入:words = ["a","aa","aaa","aaaa"]
输出:0
解释:不存在这样的两个单词。
解法一
暴力循环计算长度。哈希表缓存加速。
思路
计算长度,肯定是只能双循环,让每两个树都能计算以下长度。
关键在于,如何判断两个字符串是否含有相同的元素。
这里我的方案如下:
- 传入两个字符串a和b,判断是否有相同元素
- 新建一个哈希set,用于存字符串a的值。
- 新建一个哈希map,用于存每次比较字符串的set
- 先判断nap中是否含有a的set,没有的话就比遍历a,计算它的set,并存一份到map中
- 遍历字符串b,看b的每一项是否都能在a的set中找到,找的到就说明有重复,找不到就卓明完全不重复。
代码
/**
* @param {string[]} words
* @return {number}
*/
var maxProduct = function(words) {
let maxCount = 0;
let map = new Map();
for(let i=0;i<words.length-1;i++){
let temp = words[i];
for(let j=i+1;j<words.length;j++){
if(!isSame(words[j],temp,map)){
let newLength = temp.length * words[j].length;
maxCount = Math.max(maxCount,newLength)
}
}
}
return maxCount
};
function isSame(a, b, map) {
let set = new Set();
if(map.has(a)){
set = map.get(a)
}else{
for (let i = 0; i < a.length; i++) {
set.add(a[i]);
}
map.set(a,set);
}
for (let i = 0; i < b.length; i++) {
if (set.has(b[i])) {
return true;
}
}
return false;
}
复杂度分析
时间复杂度:O(k*n2),双循环为n2,比较为k,k为每个字符串的平均长度。
空间复杂度:O(n),为每个字符串都要存一份map和一份set
解法二
位运算。
思路
相比解法一,可优化的点就在于比较的过程。
我们其实可以利用位运算的特性来让比较的过程时间复杂度为O(1)。
我们需要提前给每个字符做好位运算掩码表。
- 遍历字符串数组,为每个字符串做处理。
- 遍历每一个字符串,对他们的每一个字符做位运算处理。
- 先计算出当前字符相对于'a'的下标差值k,通过charCodeAt计算
- 然后用1去左移位k格,如字符串'b',则1 << 2,那么b的二进制掩码为100
- 再将每一个字符的掩码和上一次的结果做 '|'处理
- 那么,如果是字符串'abc',二进制掩码则为111
- 如果是'bcf',则为100110
- 可以看出计算后的掩码表,等于就是说从右到左分别表示abcdefg...z。0表示不存在该字符,1表示存在
- 然后我们再去双循环遍历字符串数组,比较两个字符串是否有公共部分,只用那他们的二进制掩码表做'&',看结果是否是0即可,如果有公共部分,那该字符的掩码就为1,结果就不可能是0
代码
var maxProduct = function(words) {
let len = words.length;
let mask = Array(len).fill(0);
let maxCount = 0;
for(let i=0;i<len;i++){
let word = words[i]
for(let j=0;j<word.length;j++){
mask[i] = mask[i] | (1<<(word[j].charCodeAt() - 'a'.charCodeAt()))
}
}
for(let i=0;i<len-1;i++){
for(let j=i+1;j<len;j++){
if((mask[i] & mask[j]) == 0){
maxCount = Math.max(maxCount,words[i].length*words[j].length)
}
}
}
return maxCount;
};
复杂度分析
时间复杂度:O(k+n2),k为所有字符串加起来的总长度。
空间复杂度:O(n),需要申请一个数组存放字符串掩码