题目
题目来源:力扣(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 个小写字母,而整型数一共 32 位。
我们为每一个字符串使用一个长度为26的二进制数字,每一个二进制数字表示当前字符串中是否出现了这个字母;
如果两个字符串出现了相同的字母,那么这两个字符串对应的二进制数字相与结果不为0。
这里我们让整型数的每一位代表每一个字母 ,然后得到的一个整型数,它的前26位比特位用来表示字母( 1 代表有这个字母,0 代表没有这个字母)。如 “abc” 使用 ‘111’ 即数字 7代替; “abcf” 使用‘100111’ 即数字39。最后进行数字的与运算。如果哪一位相同则说明存在重复的字母,利用&运算即可。再拿“abc” 和 “abcf” 举例子 ‘111’ 和 ‘100111’ 进行与运算不为零 则说明存在相同的字母。
var maxProduct = function (words) {var getCharCodeDiff = function (char) {return char.charCodeAt(0) - 'a'.charCodeAt(0);};// 字符串数组的个数var n = words.length,// 串的长度lens = [],// 每一个串,对应一个 int,每一个串的一个字符,对应二进制的一位// 比如第一个串ab 对应00011,a对应0001等masks = [];for (var i = 0; i < n; i++) {// 每一个字符串的长度var len = words[i].length;// 记录每个字符长度,方便后面的乘积运算lens.push(len);// 记录这个串上面有的字母var mask = 0;// 把字符串的每一字符记录到 int 的某一位for (var j = 0; j < len; j++) {// 通过函数或者字符要记录在int的哪一位上,然后通过左移,把这个位标记为1// 然后与原临时进行 |运算,|运算会保留原来是1的是,记录不会丢失,有的话还是有,没有的话就加上mask |= 1 << getCharCodeDiff(words[i][j]);}// 把记录好的tmp保存到数组中,代表一个字符串masks.push(mask);}// 最大长度乘积var max = 0;// 遍历代表字符串的int数组,与后面的串所代表的int进行判断,没有重复就求乘积for (var i = 0; i < n; i++) {for (var j = i + 1; j < n; j++) {// 映射后进行 & 运算,如果所有位置都没有重复,那么结果会是零if ((masks[i] & masks[j]) == 0) {// 计算乘积,选择大的max = Math.max(max, lens[i] * lens[j]);}}}return max;};
