单词长度的最大乘积

6 阅读4分钟

题目背景

给定一个字符串数组 words,要找到两个不含相同字母的单词,使它们长度乘积最大,返回这个乘积。

方法一:用哈希表记录字符串中出现的字符

这个程序做的事:

  1. 先用 flags 表记每个单词包含哪些字母
  2. 两两比较单词,看是否有公共字母
  3. 如果没有,计算长度乘积
  4. 返回最大值
public class A_MaxProduct {
    public int maxProduct(String[] words) {//输入是一个字符串数组 `words`
        boolean[][] flags = new boolean[words.length][26];//创建二维数组 `flags`
        for (int i = 0; i < words.length; i++) {//遍历每个单词的每个字母
            for (char c: words[i].toCharArray()) {//循环‘字符串转化的字符数组’
                flags[i][c - 'a'] = true;//如果有,就把对应位置标记为 `true`
            }
        }
        int result = 0;//初始化最大乘积
        for (int i = 0; i < words.length; i++) {
            for (int j = i + 1; j < words.length; j++) {//双重循环,枚举所有不重复的单词对(i<j)
                int k = 0;
                for (; k < 26; k++) {
                    if (flags[i][k] && flags[j][k]) {//判断这两个单词是否有相同字母
                        break;//如果发现两个单词都有同一个字母,就`break`
                    }
                }
                //如果没有公共字母,就计算长度乘积
                if (k == 26) {
                    int prod = words[i].length() * words[j].length();//如果 k==26,说明没提前 break → 两个单词没有公共字母
                    result = Math.max(result, prod);//就计算长度乘积,更新最大值
                }
            }
        }


        return result;
    }
    public static void main(String[] args) {
        A_MaxProduct obj = new A_MaxProduct();
        String[] words = {"abcw", "baz", "foo", "bar", "xtfn", "abcdef"};
        int ans = obj.maxProduct(words);
        System.out.println("Max Product: " + ans);
    }
}
for (int i = 0; i < words.length; i++) {
    for (char c: words[i].toCharArray()) {
        flags[i][c - 'a'] = true;
    }
words[i]表示当前单词,比如第 i 个单词 "abcw"
words[i].toCharArray()把字符串转成一个 char[](字符数组)

"abcw".toCharArray() → ['a','b','c','w']

for (char c: words[i].toCharArray())

循环这个字符数组:

  • 第一次 c='a'
  • 第二次 c='b'
  • 第三次 c='c'
  • 第四次 c='w'

flags[i][c - 'a'] = true;

c - 'a' 是为了把字符变成数字索引:

  • 'a' - 'a' = 0
  • 'b' - 'a' = 1
  • 'c' - 'a' = 2
  • 'w' - 'a' = 22

所以:

  • flags[i][0]=true 表示单词 words[i] 有字母 'a'
  • flags[i][1]=true 表示单词 words[i] 有字母 'b'
  • flags[i][2]=true 表示单词 words[i] 有字母 'c'
  • flags[i][22]=true 表示单词 words[i] 有字母 'w'

结果:

  • flags[i] 是长度26的布尔数组
  • 每个位置代表一个字母 a~z
  • 如果单词里有这个字母 → 就是 true,没有就是 false
int k = 0;
for (; k < 26; k++) {
    if (flags[i][k] && flags[j][k]) {
        break;
    }

比如:

  • words[i] 是 "abc" → flags[i][0]=true, flags[i][1]=true, flags[i][2]=true
  • words[j] 是 "def" → flags[j][3]=true, flags[j][4]=true, flags[j][5]=true

遍历 k:

  • k=0:flags[i][0]=true,但 flags[j][0]=false → 不满足
  • k=1:flags[i][1]=true,但 flags[j][1]=false → 不满足
  • k=2:flags[i][2]=true,但 flags[j][2]=false → 不满足
  • k=3:flags[i][3]=false → 不满足
    ...
    一直到 k=25 都不满足

循环结束后:k=26

截屏2025-07-02 15.02.03.png

方法二:用整数的二进制数位记录字符串中出现的字符

位运算优化版本

位运算版本相比 boolean[][]:

  • 空间只用 int[],更小
  • 比较两个单词是否有公共字母,只需一次 flags[i]&flags[j],更快

flags[i] |= 1 << (c - 'a');

就是用一个 int 的 26 位来记录每个单词有哪些字母,用位运算让比较更快

第一次遇到 'a':

  • 'a' - 'a' = 0
  • 1 << 0 就是把第 0 个位置放一个 1:

000...0001也就是只最右边一个 1。

用 flags[i] |=(或者叫“打勾”):

  • 如果原本是 000...0000
  • 和 000...0001 做“或运算”,结果就是 000...0001

表示“我有 a” ✅

第二次遇到 'b':

  • 'b' - 'a' = 1
  • 1 << 1 = 000...0010

和刚才的结果 000...0001 做“或运算”:

000...0001

|

000...0010

=

000...0011 表示我有 a 和 b。

第三次遇到 'c':

  • 'c' - 'a' = 2
  • 1 << 2 = 000...0100

再做“或运算”: 000...0011

|

000...0100

=

000...0111表示我有 a,b,c

使用位运算将每个单词的字符集合编码为一个整型 bitmask,
然后用按位与(&)快速判断两个单词是否有公共字符

public class A_MaxProduct_1 {
    public int maxProduct(String[] words) {
        int[] flags = new int[words.length];
        for (int i = 0; i < words.length; i++) {
            for (char c : words[i].toCharArray()) {
                flags[i] |= 1 << (c - 'a');
            }
        }
        int result = 0;
        for (int i =0; i < words.length; i++) {
            for (int j = i + 1; j < words.length; j++) {
                if ((flags[i] & flags[j]) == 0) {
                    int prod = words[i].length() * words[j].length();
                    result = Math.max(result, prod);
                }
            }
        }
        return result;
    }
    public static void main(String[] args) {
        A_MaxProduct_1 obj = new A_MaxProduct_1();
        String[] words = {"abcw", "baz", "foo", "bar", "xtfn", "abcdef"};
        int ans = obj.maxProduct(words);
        System.out.println("Max product: " + ans);
    }
}

截屏2025-07-02 15.02.03.png