LeetCode 318. Maximum Product of Word Lengths

@(LeetCode)

问题描述

给定一个字符串数组 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 
解释:
不存在这样的字符串

想看英文描述的戳这里。

解题思路

常规思路

以常规思路来解,还是挺简单的。

遍历所有可能的字符串组合,对比两个字符串是否存在相同字符即可。

但这种方式效率不太高,因为需要每次都要比较是否存在相同的字符。

位操作

一种比较巧妙的思路,利用二进制位操作,非常简单的计算出字符串是否有相同的字符。

因为字符串全是小写字母,所以字符集最多为 26 个,完全可以用 26 位二进制来表示出现过的字符。

主要思路如下:

  • 26 位二进制表示出现过的字符,在字符对应的位上填 1,其他填 0
  • 两个二进制数进行与运算,如果为 0,则表示无公共字符。

下面来具体解释一下。

  1. 假设有 26 个空位,分别对照 a~z。将字符串中出现的字符,在对应的位置上填上 1,未出现的默认填 0,那么可以得到一串 1/0 组成的数字,可将其看做一组二进制位。

    比如 abc 可表示为:

    a b c d e f g h i j k l m n o p q r s t u v w x y z
    1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
    

    baz:

    11000000000000000000000001
    

    foo:

    00000100000000100000000000
    
  2. 如果两个字符串没有公共字符,与运算肯定为 0

    为了方便理解,这里的栗子,a 是在最高位。在进行位计算时,需要将 1 左移 25 - (ch - 'a') 后,再与原值相或,得到的整数就是该字符串的位表示,存入数组即可。比如 a,需要将 1 左移 25 位,才能在最高位填上 1;同理,b 左移 24 位。

二进制数计算如下:

i = 0
while (i < words.length) {
    const word = words[i]

    let val = 0
    let j = 0
    while (j < word.length) {
        const ch = word[j]
        
        const dis = ch.charCodeAt() - 'a'.charCodeAt()

        // 将字符对应的位置填上 1
        val |= 1 << (25 - dis)
        j += 1
    }

    mask[i] = val

    i += 1
}

判断是否有相同字符:

i = 0
while (i < words.length - 1) {
    const word1 = words[i]

    let j = i + 1
    while (j < words.length) {

        const word2 = words[j]

        // 按位与,不存在相同字符,注意加括号
        if ((mask[i] & mask[j]) === 0) {
            const product = word1.length * word2.length
            if (product > maxLen) {
                maxLen = product
            }
        }

        j += 1
    }

    i += 1
}

你可能感兴趣的:(LeetCode 318. Maximum Product of Word Lengths)