位运算题目:最大单词长度乘积
文章目录
- 题目
- 标题和出处
- 难度
- 题目描述
- 要求
- 示例
- 数据范围
- 解法
- 思路和算法
- 代码
- 复杂度分析
题目
标题和出处
标题:最大单词长度乘积
出处:318. 最大单词长度乘积
难度
4 级
题目描述
要求
给定一个字符串数组 words \texttt{words} words,返回 length(words[i]) × length(words[j]) \texttt{length(words[i])} \times \texttt{length(words[j])} length(words[i])×length(words[j]) 的最大值,并且这两个单词不含有公共字母。如果不存在这样的两个单词,返回 0 \texttt{0} 0。
示例
示例 1:
输入:
words
=
["abcw","baz","foo","bar","xtfn","abcdef"]
\texttt{words = ["abcw","baz","foo","bar","xtfn","abcdef"]}
words = ["abcw","baz","foo","bar","xtfn","abcdef"]
输出:
16
\texttt{16}
16
解释:这两个单词为
"abcw"
\texttt{"abcw"}
"abcw"、
"xtfn"
\texttt{"xtfn"}
"xtfn"。
示例 2:
输入:
words
=
["a","ab","abc","d","cd","bcd","abcd"]
\texttt{words = ["a","ab","abc","d","cd","bcd","abcd"]}
words = ["a","ab","abc","d","cd","bcd","abcd"]
输出:
4
\texttt{4}
4
解释:这两个单词为
"ab"
\texttt{"ab"}
"ab"、
"cd"
\texttt{"cd"}
"cd"。
示例 3:
输入:
words
=
["a","aa","aaa","aaaa"]
\texttt{words = ["a","aa","aaa","aaaa"]}
words = ["a","aa","aaa","aaaa"]
输出:
0
\texttt{0}
0
解释:不存在这样的两个单词。
数据范围
- 2 ≤ words.length ≤ 1000 \texttt{2} \le \texttt{words.length} \le \texttt{1000} 2≤words.length≤1000
- 1 ≤ words[i].length ≤ 1000 \texttt{1} \le \texttt{words[i].length} \le \texttt{1000} 1≤words[i].length≤1000
- words[i] \texttt{words[i]} words[i] 只包含小写英语字母
解法
思路和算法
为了得到最大单词长度乘积,需要遍历数组 words \textit{words} words 中的每一对单词,判断两个单词是否含有公共字母,如果没有公共字母则计算这两个单词长度的乘积。对于长度为 n n n 的数组 words \textit{words} words,遍历每一对单词需要 O ( n 2 ) O(n^2) O(n2) 的时间,如果通过遍历两个单词判断两个单词是否含有公共字母,则时间复杂度高于 O ( n 2 ) O(n^2) O(n2)。为了降低时间复杂度,需要在 O ( 1 ) O(1) O(1) 的时间内判断两个单词是否含有公共字母,则时间复杂度是 O ( n 2 ) O(n^2) O(n2)。
为了在 O ( 1 ) O(1) O(1) 的时间内判断两个单词是否含有公共字母,需要使用位运算。由于每个单词只包含小写英语字母,共有 26 26 26 个字母,因此每个单词可以使用 26 26 26 位二进制数表示该单词中出现的字母。具体表示方法是,二进制表示从低到高的第 0 0 0 位到第 25 25 25 位的每一位分别表示单词中是否出现 a \text{a} a 到 z \text{z} z 的每个字母,如果一个二进制位是 1 1 1 则表示该位对应的字母在单词中出现,如果一个二进制位是 0 0 0 则表示该位对应的字母不在单词中出现。
得到每个单词的二进制表示之后,判断两个单词是否含有公共字母时,可以计算这两个单词对应的二进制表示的按位与运算结果。如果按位与运算结果是 0 0 0,则这两个单词不含有公共字母;如果按位与运算结果不是 0 0 0,则这两个单词含有公共字母,按位与运算结果中不是 0 0 0 的位表示公共字母。只有当按位与运算结果是 0 0 0 时,才需要计算这两个单词长度的乘积,并更新最大单词长度乘积。
代码
class Solution {
public int maxProduct(String[] words) {
int length = words.length;
int[] masks = new int[length];
for (int i = 0; i < length; i++) {
String word = words[i];
int wordLength = word.length();
for (int j = 0; j < wordLength; j++) {
char c = word.charAt(j);
masks[i] |= 1 << (c - 'a');
}
}
int maxValue = 0;
for (int i = 0; i < length; i++) {
for (int j = i + 1; j < length; j++) {
if ((masks[i] & masks[j]) == 0) {
int value = words[i].length() * words[j].length();
maxValue = Math.max(maxValue, value);
}
}
}
return maxValue;
}
}
复杂度分析
-
时间复杂度: O ( n 2 + L ) O(n^2 + L) O(n2+L),其中 n n n 是数组 words \textit{words} words 的长度, L L L 是数组 words \textit{words} words 中的所有单词的长度之和。计算每个单词的二进制表示需要 O ( L ) O(L) O(L) 的时间遍历所有单词,计算最大单词长度乘积需要 O ( n 2 ) O(n^2) O(n2) 的时间遍历每一对单词,因此时间复杂度是 O ( n 2 + L ) O(n^2 + L) O(n2+L)。
-
空间复杂度: O ( n ) O(n) O(n),其中 n n n 是数组 words \textit{words} words 的长度。需要创建长度为 n n n 的数组存储每个单词的二进制表示。