- 思路一
- 题目关键在于判断两个字符串是否存在相同的字母,首先想到的就是给每一个字符串关联一个Set,记录字符串出现的所有字母,但是由于只有26个小写字母,所以也可以给每一个字符串关联一个长度为26的boolean数组,用来记录字母是否出现,所以整体需要一个二位boolean数组
- 在记录完毕后根据数组内容来判断两个字符串是否有相同字母
- 时空复杂度:设数组长度为n,字符串平均长度为k,初始化flag时间复杂度为O(nk),下面判断的过程时间复杂度为O(n²),所以整体时间复杂度为O(n²);额外空间为二维boolean数组,由于其中一个维度的长度是26,所以可以看作O(n)
public int maxProduct(String[] words) {
int result = 0;
boolean[][] flags = new boolean[words.length][26];
//初始化flag
for (int i = 0; i < words.length; i++) {
for (Character c : words[i].toCharArray()) {
flags[i][c - 'a'] = true;
}
}
for (int i = 0; i < flags.length; i++) {
for (int j = i; j < flags.length; j++) {
//判断words[i]和words[j]是否存在相同的字母
int k = 0;
for (; k < 26; k++) {
//如果存在一样的字母
if (flags[i][k] && flags[j][k])
break;
}
result = (26 == k) ? Math.max(words[i].length() * words[j].length(), result) : result;
}
}
return result;
}
- 思路二
- 字母只有26个,而一个int有32位,我们可以用某一位的0或者1表示是否包含某字母,26个字母对应int的低26位,所以一个字符串对应一个int值,只需要一个int数组即可
需要注意的是初始化flags数组和最后判断时的写法 - 时空复杂度:设字符串的长度是k,数组长度为n,上方遍历O(nk),下方判断O(n²),平均O(n²);额外空间为一个int数组,长度为n,所以空间复杂度为O(n)
- 字母只有26个,而一个int有32位,我们可以用某一位的0或者1表示是否包含某字母,26个字母对应int的低26位,所以一个字符串对应一个int值,只需要一个int数组即可
public int maxProduct(String[] words) {
int result = 0;
int[] flags = new int[words.length];
for (int i = 0; i < words.length; i++) {
for (Character c : words[i].toCharArray()) {
flags[i] |= 1 << c - 'a';
}
}
for (int i = 0; i < flags.length; i++) {
for (int j = i; j < flags.length; j++) {
result = (0 == (flags[i] & flags[j])) ? (Math.max(words[i].length() * words[j].length(), result)) : result;
}
}
return result;
}
补充
-
不管是何种思路,在初始化flag数组时都有两种选择
- 遍历字母表,每一个字母判断一次是否存在于字符串中
- 遍历字符串,把字母直接填入
设字符串的长度是k,数组长度为n,对于第一种方法,遍历字母表次数是26,每一次判断该字母是否存在于字符串的平均时间复杂度是O(k/2),所以平均下来是O(13nk)
对于第二种方法,就是简单的遍历,平均时间复杂度为O(nk),所以在初始化时选择了第二种方法