原题目:
给定一个字符串数组,找到长度的最大值length(word[i]) * length(word[j])
,其中两个单词中的字母无相同。您能够假定每一个单词只包含小写字母。若是没有这两个词,返回0。数组
例:编码
Input: ["abcw","baz","foo","bar","xtfn","abcdef"] Output: 16 Explanation: The two words can be "abcw", "xtfn".
解析:
这题确定要进行交叉对比(2个for循环),但最关键的就是对比过程,也就是判断2个字符串是否存在相同的字符。code
若是使用indexOf
或者数组下标记录都会形成时间复杂度大幅提高,看了他人的答案发现使用的是位操做符<<
,|
和&
,并且是在交叉对比以前进行预处理,交叉对比的时候只须要简单的判断pretreate[i] & pretreate[j]===0
即可,leetcode
由于使用后效率提高太多,解析而且记录一下。字符串
先解释val |= (1 << (word.charCodeAt(i)-aCode))
:get
word.charCodeAt(i)-aCode
这个很好懂,也就是a对应0,b对应1...这里的0,1数字表明的是 1<<0
,1<<1
是什么呢?1在二进制中(32位)就是00000000000000000000000000000001
,<<
是左移1位,string
那么1<<0
仍是1
,1<<1
就是(前面的零省略)10
,1<<2
就是100
,1<<3
就是1000
,io
因而可知for循环
a
就是1
,function
b
是10
,
c
是100
...
z
是10000000000000000000000000
(25个0)。
|
是按位或:二进制编码中,每一位二者其中一个为1,则为1,不然,则为0,所以 val |=
就是对每个字符合并,例如
ab
是 00010|00001
=>00011
,
f
是 100000
,
ffff
也是 100000
,
big
是 101000010
,
axdg
是100000000000000001001001
。
&
,按位与,二进制编码中,每一位二者都为1,则为1,不然,则为0,
例1:axdg
和oigd
要判断是否有重复:
axdg是:100000000000000001001001 oifd是: 100000100101000 & 后: 000000000000000000001000
由于第4位都为1,因此最后不为0,也可得知重复的就是字母表第4位:d
。
例2:axdg
和lkmk
要判断是否有重复:
结果为0,说明无重复。
axdg是:100000000000000001001001 lkmk是: 1110000000000 & 后: 000000000000000000000000
总结:这种方法使用了二进制数字的位数做为保存字符的手段,相比起数组,散列表等,速度更快,在保存量较小(<=32)优点很是明显。
代码:
/** * @param {string[]} words * @return {number} */ var maxProduct = function(words) { let aCode='a'.charCodeAt(0) function compute(word){ let val=0 for(let i=0;i<word.length;i++){ val |= (1 << (word.charCodeAt(i)-aCode)) } return val } let pretreatment=[] for(let i=0;i<words.length;i++){ pretreatment[i]=compute(words[i]) } let maxSum=0 for(let i=0;i<words.length-1;i++){ for(let j=i+1;j<words.length;j++){ let len1=words[i].length,len2=words[j].length if(len1*len2>maxSum && (pretreatment[i] & pretreatment[j])===0){ maxSum=len1*len2 } } } return maxSum };