最大单词长度乘积
难度:
标签:
题目描述
给你一个字符串数组 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 解释
:不存在这样的两个单词。
提示:
2 <= words.length <= 1000
1 <= words[i].length <= 1000
words[i]
仅包含小写字母
代码结果
运行时间: 174 ms, 内存: 19.0 MB
/*
思路:
1. 使用流来处理数组,计算每个单词的位掩码和长度。
2. 使用流生成的组合,过滤掉有公共字母的组合。
3. 计算长度乘积,并使用最大值收集器获得最大值。
*/
import java.util.stream.IntStream;
import java.util.stream.Stream;
public class Solution {
public int maxProduct(String[] words) {
int n = words.length;
int[] masks = new int[n];
int[] lens = new int[n];
IntStream.range(0, n).forEach(i -> {
masks[i] = words[i].chars().reduce(0, (mask, c) -> mask | (1 << (c - 'a')));
lens[i] = words[i].length();
});
return IntStream.range(0, n)
.boxed()
.flatMap(i -> IntStream.range(i + 1, n).mapToObj(j -> new int[]{i, j}))
.filter(pair -> (masks[pair[0]] & masks[pair[1]]) == 0)
.mapToInt(pair -> lens[pair[0]] * lens[pair[1]])
.max()
.orElse(0);
}
}
解释
方法:
这个题解采用了位运算和哈希表的思路。首先用一个哈希表记录每个单词出现过的字符所对应的二进制掩码,以及该掩码对应的最大单词长度。然后通过双重循环枚举哈希表中的所有掩码对,如果两个掩码按位与的结果为0,说明它们对应的单词没有公共字母,此时更新最大乘积结果。
时间复杂度:
O(nm)
空间复杂度:
O(1)
代码细节讲解
🦆
在使用位运算表示字符掩码时,你是如何保证即使单词中包含相同的字母也只计算一次掩码?
▷🦆
为什么在哈希表中保存字符掩码对应的最大长度而不是保存所有可能的长度?
▷🦆
题解中提到哈希表的大小最多为2^26,这是如何得出的?为什么是2^26而不是其他数?
▷🦆
在比较两个字符掩码时,为什么使用按位与操作(&)来检查两个单词是否有公共字母?
▷