剑指 Offer II 005. 单词长度的最大乘积
题目描述
给定一个字符串数组 words,请计算当两个字符串 words[i] 和 words[j] 不包含相同字符时,它们长度的乘积的最大值。假设字符串中只包含英语的小写字母。如果没有不包含相同字符的一对字符串,返回 0。
解法
保存每一个字符串的掩码
由于字符串中只包含小写字母,这个字符串中最多只能包含26种不同字母吗,所以我们可以使用26位掩码来表示这个字符串中包含的字符,规定字符’a’对应第0位,字符’z’对应第25位。 对于两个完全不同字符串(非空串,对应掩码非0)对应的的掩码mask1和mask2,mask1 & mask2的结果一定为0,如果包含相同的字符,结果一定非0。 根据这个规则,我们可以化简字符串比较的时间复杂度,这样总体的时间复杂度只是嵌套循环取两字字符串,即O(n2 )。 算法描述:
将每一个字符串转换为掩码后保存,遍历每一对掩码进行按位与的操作,找出按位与结果为0的长度乘积最大值。
function getLetterIndex ( s ) {
return s. charCodeAt ( 0 ) - 'a' . charCodeAt ( 0 )
}
function transferWord2Bit ( word ) {
let result = 0
for ( let i = 0 ; i < word. length; i++ ) {
result |= 1 << getLetterIndex ( word. charAt ( i) )
}
return result
}
var maxProduct = function ( words ) {
const wordsBits = words. map ( word => transferWord2Bit ( word) )
let max = 0
for ( let i = 0 ; i < wordsBits. length; i++ ) {
for ( let j = i + 1 ; j < wordsBits. length; j++ ) {
if ( ! ( wordsBits[ i] & wordsBits[ j] ) ) {
max = Math. max ( max, words[ i] . length * words[ j] . length)
}
}
}
return max
} ;
记录掩码和最长字符串长度的映射
按上面的思路,我们把字符串转化为掩码,保存了所有字符串的掩码。但是,对于abcd和aabbccdd来说,它们的掩码都是00000000000000000000001111,我们只需要aabbccdd,对于abcd,会进行相同的掩码比较且因为它比较短而被舍弃,这一点是可以先前预料并且进行改进的。 改进:可以只保存 { 掩码: 字符串最长长度 },掩码的数量是 <= 字符串数量的,所以时间复杂度比O(n2 )小。
保存Map{ 掩码: 字符串最长长度 }:
计算每一个字符串的掩码。 如果map中没有该掩码,就存储该字符串长度; 如果有且该字符串长度大于map中掩码对应长度,就更新。 const maskMap = new Map ( )
words. map ( word => {
const wordLength = word. length
const wordMask = transferWord2Bit ( word)
if ( wordLength > ( maskMap. get ( wordMask) || 0 ) ) {
maskMap. set ( wordMask, wordLength)
}
} )
遍历map中所有的掩码map.keys(),如果一对掩码完全不同,则计算其长度对乘积并更新结果值。const wordMasks = Array. from ( maskMap. keys ( ) )
for ( const mask1 of wordMasks) {
const maxWord1Length = maskMap. get ( mask1)
for ( const mask2 of wordMasks) {
const maxWord2Length = maskMap. get ( mask2)
if ( ! ( mask2 & mask1) ) {
max = Math. max ( max, maxWord1Length * maxWord2Length)
}
}
}
` ` `
var maxProduct = function ( words ) {
const maskMap = new Map ( )
words. map ( word => {
const wordLength = word. length
const wordMask = transferWord2Bit ( word)
if ( wordLength > ( maskMap. get ( wordMask) || 0 ) ) {
maskMap. set ( wordMask, wordLength)
}
} )
let max = 0
const wordMasks = Array. from ( maskMap. keys ( ) )
for ( const mask1 of wordMasks) {
const maxWord1Length = maskMap. get ( mask1)
for ( const mask2 of wordMasks) {
const maxWord2Length = maskMap. get ( mask2)
if ( ! ( mask2 & mask1) ) {
max = Math. max ( max, maxWord1Length * maxWord2Length)
}
}
}
return max
}