1.题目描述
给定一个字符串数组 words,请计算当两个字符串 words[i] 和 words[j] 不包含相同字符时,它们长度的乘积的最大值。假设字符串中只包含英语的小写字母。如果没有不包含相同字符的一对字符串,返回 0。
示例 1:
输入: words = ["abcw","baz","foo","bar","fxyz","abcdef"]
输出: 16
解释: 这两个单词为 "abcw", "fxyz"。它们不包含相同字符,且长度的乘积最大。
示例 2:
输入: words = ["a","ab","abc","d","cd","bcd","abcd"]
输出: 4
解释: 这两个单词为 "ab", "cd"。
示例 3:
输入: words = ["a","aa","aaa","aaaa"]
输出: 0
解释: 不存在这样的两个单词。
2.解题思路与代码
2.1 解题思路
首先要确定一个单词里面出现了那些字母,然后再依次比较单词中出现的字母是否重复,那么这里就可以考虑使用位运算来解答。我们知道一个 int 整数是 32 位的,而小写字母共 26 位,那么我们就可以使用整型的 26 位来分别表示从 a 到 z 的字母是否出现:0 表示没有出现,1 表示出现。以 “abc” 为例,首先我们初始化一个 num1=0,这个时候 num1 的每一位都为 0.
然后我们开始遍历 “abc” ,第一位取到 ‘a’ ,将 num1 上的位数从 0 开始依次表示字母 a 到 z ,因此字母 a 所在的位置是在 ‘a’-‘a’ 第 0 位,于是使用 1 左移 0 位并与 num1 进行或运算将第 0 位 1 赋值给 num1
之后遍历到 b,此时 b 应当在第 1 位,于是将 1 左移 1 位后再与 num1 或运算,如下图所示
同理遍历对 c 进行处理
此时我们将 a、b、c 三个字母是否出现定义给了 num1 的前三位。同理我们对 “xyz” 进行赋值得到 num2,得到下图
在得到每个单词的字幕出现情况之后,便可以通过与运算比较两个单词中是否有重复字母。例如我们要比较 “abc” 和 “xyz” 是否包含重复字母,直接将 num1 和 num2 按位与运算,由于与运算都为 1 才是 1 ,那么如果每一位都不同,那么必然结果为 0 ,如果不为 0 那么一定存在重复字母。
2.2 代码
class Solution {
public int maxProduct(String[] words) {
int n = words.length;
int[] tmp = new int[n];
for (int i = 0; i < n; i++) {
int num = 0;
for (int j = 0; j < words[i].length(); j++) {
// 通过位运算记录字母是否出现
num |= 1 << (words[i].charAt(j) - 'a');
}
tmp[i] = num;
}
int max = 0;
for (int i = 0; i < n - 1; i++) {
for (int j = i + 1; j < n; j++) {
// 依次求与运算,如果结果等于零表示两个单词没有重复字母,此时计算长度乘积最大值
if ((tmp[i] & tmp[j]) == 0) {
max = Math.max(max, words[i].length() * words[j].length());
}
}
}
return max;
}
}
2.3 测试结果
通过测试
3.总结
- 首先使用位来记录单词中字母出现情况
- 依次按位求与运算, 如果结果是 0 表示两个单词中没有相同字母;不为 0 表示一定有相同字母