318. Maximum Product of Word Lengths

我用了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(){
            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

你可能感兴趣的:(318. Maximum Product of Word Lengths)