var maxProduct = function(words) { const length = words.length; const masks = newArray(length).fill(0); for (let i = 0; i < length; i++) { const word = words[i]; const wordLength = word.length; for (let j = 0; j < wordLength; j++) { masks[i] |= 1 << (word[j].charCodeAt() - 'a'.charCodeAt()); } } let maxProd = 0; for (let i = 0; i < length; i++) { for (let j = i + 1; j < length; j++) { if ((masks[i] & masks[j]) === 0) { maxProd = Math.max(maxProd, words[i].length * words[j].length); } } } return maxProd; };
[sol1-Golang]
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
funcmaxProduct(words []string) (ans int) { masks := make([]int, len(words)) for i, word := range words { for _, ch := range word { masks[i] |= 1 << (ch - 'a') } }
for i, x := range masks { for j, y := range masks[:i] { if x&y == 0 && len(words[i])*len(words[j]) > ans { ans = len(words[i]) * len(words[j]) } } } return }
[sol1-Python3]
1 2 3 4
classSolution: defmaxProduct(self, words: List[str]) -> int: masks = [reduce(lambda a, b: a | (1 << (ord(b) - ord('a'))), word, 0) for word in words] returnmax((len(x[1]) * len(y[1]) for x, y in product(zip(masks, words), repeat=2) if x[0] & y[0] == 0), default=0)
复杂度分析
时间复杂度:$O(L + n^2)$,其中 $L$ 是数组 words 中的全部单词长度之和,$n$ 是数组 words 的长度。预处理每个单词的位掩码需要遍历全部单词的全部字母,时间复杂度是 $O(L)$,然后需要使用两重循环遍历位掩码数组 masks 计算最大单词长度乘积,时间复杂度是 $O(n^2)$,因此总时间复杂度是 $O(L + n^2)$。
空间复杂度:$O(n)$,其中 $n$ 是数组 words 的长度。需要创建长度为 $n$ 的位掩码数组 masks。
方法二:位运算优化
方法一需要对数组 words 中的每个单词计算位掩码,如果数组 words 中存在由相同的字母组成的不同单词,则会造成不必要的重复计算。例如单词 meet 和 met 包含的字母相同,只是字母的出现次数和单词长度不同,因此这两个单词的位掩码表示也相同。由于判断两个单词是否有公共字母是通过判断两个单词的位掩码的按位与运算实现,因此在位掩码相同的情况下,单词的长度不会影响是否有公共字母,当两个位掩码的按位与运算等于 $0$ 时,为了得到最大单词长度乘积,这两个位掩码对应的单词长度应该尽可能大。根据上述分析可知,如果有多个单词的位掩码相同,则只需要记录该位掩码对应的最大单词长度即可。
funcmaxProduct(words []string) (ans int) { masks := map[int]int{} for _, word := range words { mask := 0 for _, ch := range word { mask |= 1 << (ch - 'a') } iflen(word) > masks[mask] { masks[mask] = len(word) } }
for x, lenX := range masks { for y, lenY := range masks { if x&y == 0 && lenX*lenY > ans { ans = lenX * lenY } } } return }
[sol2-Python3]
1 2 3 4 5 6 7
classSolution: defmaxProduct(self, words: List[str]) -> int: masks = defaultdict(int) for word in words: mask = reduce(lambda a, b: a | (1 << (ord(b) - ord('a'))), word, 0) masks[mask] = max(masks[mask], len(word)) returnmax((masks[x] * masks[y] for x, y in product(masks, repeat=2) if x & y == 0), default=0)
复杂度分析
时间复杂度:$O(L + n^2)$,其中 $L$ 是数组 words 中的全部单词长度之和,$n$ 是数组 words 的长度。预处理每个单词的位掩码并将位掩码对应的最大单词长度存入哈希表需要遍历全部单词的全部字母,时间复杂度是 $O(L)$,然后需要使用两重循环遍历哈希表计算最大单词长度乘积,时间复杂度是 $O(n^2)$,因此总时间复杂度是 $O(L + n^2)$。
空间复杂度:$O(n)$,其中 $n$ 是数组 words 的长度。需要创建哈希表记录每个位掩码对应的最大单词长度,哈希表中的记录数量不会超过 $n$。