[路飞]_leetcode刷题_318. 最大单词长度乘积

166 阅读2分钟

「这是我参与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 
解释:不存在这样的两个单词。

解法一

暴力循环计算长度。哈希表缓存加速。

思路

计算长度,肯定是只能双循环,让每两个树都能计算以下长度。

关键在于,如何判断两个字符串是否含有相同的元素。

这里我的方案如下:

  1. 传入两个字符串a和b,判断是否有相同元素
  2. 新建一个哈希set,用于存字符串a的值。
  3. 新建一个哈希map,用于存每次比较字符串的set
  4. 先判断nap中是否含有a的set,没有的话就比遍历a,计算它的set,并存一份到map中
  5. 遍历字符串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)。

我们需要提前给每个字符做好位运算掩码表。

  1. 遍历字符串数组,为每个字符串做处理。
  2. 遍历每一个字符串,对他们的每一个字符做位运算处理。
    • 先计算出当前字符相对于'a'的下标差值k,通过charCodeAt计算
    • 然后用1去左移位k格,如字符串'b',则1 << 2,那么b的二进制掩码为100
    • 再将每一个字符的掩码和上一次的结果做 '|'处理
    • 那么,如果是字符串'abc',二进制掩码则为111
    • 如果是'bcf',则为100110
    • 可以看出计算后的掩码表,等于就是说从右到左分别表示abcdefg...z。0表示不存在该字符,1表示存在
  3. 然后我们再去双循环遍历字符串数组,比较两个字符串是否有公共部分,只用那他们的二进制掩码表做'&',看结果是否是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),需要申请一个数组存放字符串掩码