2021.11.17LeetCode每日一题——最大单词长度乘积

目录

最大单词长度乘积

描述

示例 1

示例 2

示例 3

提示

方法一:位运算

方法二:位运算优化


最大单词长度乘积

描述

给定一个字符串数组 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"。

示例 3

输入: ["a","aa","aaa","aaaa"]
输出: 0 
解释: 不存在这样的两个单词。

提示

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

方法一:位运算

为了得到最大单词长度乘积,朴素的做法是,遍历字符串数组 \textit{words}words 中的每一对单词,判断这一对单词是否有公共字母,如果没有公共字母,则用这一对单词的长度乘积更新最大单词长度乘积。

用 n 表示数组 words 的长度,用 l_i 表示单词 words[i] 的长度,其中 0≤i的时间判断是否有公共字母和计算长度乘积。因此上述做法的时间复杂度是

O(\sum_{0\le i<j<n}l_i \times l_j)

该时间复杂度高于 O(n^2)

如果可以将判断两个单词是否有公共字母的时间复杂度降低到 O(1),则可以将总时间复杂度降低到 O(n^2)

可以使用位运算预处理每个单词,通过位运算操作判断两个单词是否有公共字母。由于单词只包含小写字母,共有 26 个小写字母,因此可以使用位掩码的最低 26 位分别表示每个字母是否在这个单词中出现。将 a 到 z 分别记为第 0 个字母到第 25 个字母,则位掩码的从低到高的第 i 位是 1 当且仅当第 i 个字母在这个单词中,其中 0≤i≤25。

用数组 masks 记录每个单词的位掩码表示。计算数组 masks 之后,判断第 i 个单词和第 j 个单词是否有公共字母可以通过判断 masks[i] & masks[j] 是否等于 0 实现,当且仅当 masks[i] & masks[j]=0 时第 i 个单词和第 j 个单词没有公共字母,此时使用这两个单词的长度乘积更新最大单词长度乘积。

class Solution {
    public int maxProduct(String[] words) {
        int len=words.length;
        int[] masks=new int[len];
        for (int i=0;i

2021.11.17LeetCode每日一题——最大单词长度乘积_第1张图片

 

方法二:位运算优化

从上述过程中我们可以发现,单词"meet"和单词"met"的mask掩码值相等,因为他们都包含了字母"m"、"e"、"t",所以此时我们只需要保留较大的长度单词"meet"即可。这个操作可以用哈希表实现。

我们可以使用哈希表记录每个位掩码对应的最大单词长度,然后遍历哈希表中的每一对位掩码,如果这一对位掩码的按位与运算等于 0,则用这一对位掩码对应的长度乘积更新最大单词长度乘积。

由于每个单词的位掩码都不等于 0,任何一个不等于 0 的数和自身做按位与运算的结果一定不等于 0,因此当一对位掩码的按位与运算等于 0 时,这两个位掩码一定是不同的,对应的单词也一定是不同的。

class Solution {
    public int maxProduct(String[] words) {
        int len=words.length;
        HashMap map=new HashMap<>();//存储每一个掩码对应的最大字符长度
        for (int i=0;imap.getOrDefault(mask,0)){//如果当前掩码值的最大长度比当前长度小
                map.put(mask,word.length());//则更新最大长度
            }
        }
        int max=0;
        for (Integer mask1 : map.keySet()) {
            for (Integer mask2 : map.keySet()) {
                if ((mask1&mask2)==0){//如果两个单词不重复
                    max=Math.max(max,map.get(mask1)*map.get(mask2));//取乘积较大值
                }
            }
        }
        return max;
    }
}

2021.11.17LeetCode每日一题——最大单词长度乘积_第2张图片

你可能感兴趣的:(#,力扣每日一题,位运算,掩码,哈希表)