我用了O(n2) brute force解法,以为会超时,结果还好。击败了11%的人。然后看了下答案,很多人用了位运算判断有没有相似字母,但是时间复杂度跟我一样呀。。可能是bit manipulation就是比较快吧。
public int maxProduct(String[] words) {
if (words == null || words.length <= 1)
return 0;
int max = 0;
for (int i = 0; i < words.length - 1; i++) {
for (int j = i + 1; j < words.length; j++) {
if (!haveCommonLetter(words[i], words[j])) {
max = Math.max(words[i].length() * words[j].length(), max);
}
}
}
return max;
}
private boolean haveCommonLetter(String s1, String s2) {
int[] map = new int[26];
for (int i = 0; i < s1.length(); i++) {
map[s1.charAt(i) - 'a']++;
}
for (int i = 0; i < s2.length(); i++) {
if (map[s2.charAt(i) - 'a'] != 0) {
return true;
}
}
return false;
}
bit manipulation的方法:
public int maxProduct(String[] words) {
if (words == null || words.length == 0)
return 0;
int len = words.length;
int[] value = new int[len];
for (int i = 0; i < len; i++) {
String tmp = words[i];
value[i] = 0;
for (int j = 0; j < tmp.length(); j++) {
value[i] |= 1 << (tmp.charAt(j) - 'a');
}
}
int maxProduct = 0;
for (int i = 0; i < len; i++)
for (int j = i + 1; j < len; j++) {
if ((value[i] & value[j]) == 0 && (words[i].length() * words[j].length() > maxProduct))
maxProduct = words[i].length() * words[j].length();
}
return maxProduct;
}
我理解了半天,确实因为bit manipulation不常用很难一眼看出来。它用了这样一句:
value[i] |= 1 << (tmp.charAt(j) - 'a');
其实就是,int有32位,字母有26个,正好还多6个,可以用了mapping;于是它就把1向左移动,a移动0位,z移动25位,这样的话比如dba就成了1011,用int表示是19。|= 这种计算很像安卓里面用来判断两个属性是不是同时存在,比如xml布局里那种。最后判断两个数是否有重叠字母就相与一下。挺fancy的,我遇到这种题一般喜欢用array模拟map,这里提供了另一种思路。
另外,还注意到另一个人写了一个带有prunning字样的代码,就是先判断两个字符串长度,再判断是不是hasCommon,可以减少几次循环,不过string.length()代码我感觉也是要for循环的吧。。。看了String的源码,没找到实现。
public class Solution {
public int maxProduct(String[] words) {
int max = 0;
Arrays.sort(words, new Comparator<String>(){
public int compare(String a, String b){
return b.length() - a.length();
}
});
int[] masks = new int[words.length]; // alphabet masks
for(int i = 0; i < masks.length; i++){
for(char c: words[i].toCharArray()){
masks[i] |= 1 << (c - 'a');
}
}
for(int i = 0; i < masks.length; i++){
if(words[i].length() * words[i].length() <= max) break; //prunning
for(int j = i + 1; j < masks.length; j++){
if((masks[i] & masks[j]) == 0){
max = Math.max(max, words[i].length() * words[j].length());
break; //prunning
}
}
}
return max;
}
}
扯的有点远了。
ref:
https://discuss.leetcode.com/topic/35539/java-easy-version-to-understand/2