返回

318. 最大单词长度乘积: 经典「状态压缩 + 位运算」入门题

后端

1. 题意理解

给出由小写字母组成的数组 words,需要你返回所有 words 中两个不相交的子数组的最大单词长度乘积。如果数组长度为 n,那么子数组的最大长度就是 n-1

2. 解题思路

这道题的关键在于对问题进行「状态压缩」,将数组 words 中的每个单词转化为一个二进制位,然后使用「位运算」来找出所有不相交子数组的单词长度乘积。

3. 详细解法

为了进行「状态压缩」,首先需要定义一个二进制位来表示每个单词。对于数组 words 中的第 i 个单词,我们将其表示为二进制位 mask[i]

  • 将每个单词转换为二进制位:

    • 将每个单词中的每个小写字母映射为一个二进制位,例如,a 映射为 00000001b 映射为 00000010,以此类推。
    • 将每个单词中的所有二进制位合并为一个二进制位 mask[i]。例如,单词 "abc" 的二进制位是 00000111
  • 使用「位运算」找出所有不相交子数组:

    • 定义一个变量 dp[i] 来存储以数组 words 中第 i 个单词结尾的所有不相交子数组的最大单词长度乘积。
    • 初始化 dp[0] = 0
    • i = 1 开始循环到 n
      • 对于数组 words 中的第 j 个单词,如果 mask[i]mask[j] 没有相同的二进制位,则说明子数组 words[i]words[j] 是不相交的。
      • 更新 dp[i]max(dp[i], dp[j] + length(words[i]) * length(words[j])),其中 length(word) 表示单词 word 的长度。
  • 返回 max(dp[1], dp[2], ..., dp[n]) 即可得到最终结果。

4. 代码示例

def maxProduct(words):
    n = len(words)
    mask = [0] * n
    dp = [0] * n
    
    for i in range(n):
        for c in words[i]:
            mask[i] |= 1 << (ord(c) - ord('a'))

    for i in range(1, n):
        for j in range(i):
            if mask[i] & mask[j] == 0:
                dp[i] = max(dp[i], dp[j] + len(words[i]) * len(words[j]))

    return max(dp)

5. 结语

这道题通过「状态压缩」和「位运算」两个技巧巧妙地解决了问题,展现了算法在解决实际问题中的强大威力。希望你能通过这道题学到新的算法技巧,并将其运用到其他的算法问题中去。