原題目:
給定一個字符串數組,找到長度的最大值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 };