一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第2天,点击查看活动详情。
前言
笔者除了大学时期选修过《算法设计与分析》和《数据结构》还是浑浑噩噩度过的(当时觉得和编程没多大关系),其他时间对算法接触也比较少,但是随着开发时间变长对一些底层代码/处理机制有所接触越发觉得算法的重要性,所以决定开始系统的学习(主要是刷力扣上的题目)和整理,也希望还没开始学习的人尽早开始。
系列文章收录《算法》专栏中。
问题描述
给定一个字符串数组 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 <= words.length <= 1000
- 1 <= words[i].length <= 1000
- words[i] 仅包含小写字母
剖析
暴力破解
看的这个题的第一反应是很简单,直接暴力破解,时间复杂度为O(n^2*m)(n为数组长度,m为平均单词长度),空间复杂度为O(1),比较简单也能通过.
/**
* 字符串数组每个字符串和其他字符串进行比较,如果不同就把两个字符串长度进行乘积,最后只保留乘积较大数。
* 每个字符串怎么比较?把字符串的每个字符抽出来看另一个字符串是否contain
*
* @param words
* @return
*/
public static int maxProduct(String[] words) {
if (words.length < 2 || words.length > 1000) {
throw new RuntimeException("字符串数组长度不符合规定长度");
}
int maxProduct = 0;
for (int i = 0; i < words.length; i++) {
for (int j = i + 1; j < words.length; j++) {
String a = words[i];
String b = words[j];
if (a.length() <= 0 || a.length() > 1000 || b.length() <= 0 || b.length() > 1000) {
throw new RuntimeException("字符串长度不符合规定长度");
}
boolean bContainA = false;
for (char ac : a.toCharArray()) {
if (b.contains(String.valueOf(ac))) {
bContainA = true;
break;
}
}
if (!bContainA) {
int tempProduct = a.length() * b.length();
maxProduct = (maxProduct < tempProduct) ? tempProduct : maxProduct;
}
}
}
return maxProduct;
}
使用位图
做算法题的时候还需要注意一些特殊的关键信息,比如这里的“假设字符串中只包含英语的小写字母。”,
- 只有26个字母,那么我是不是可以使用一个Integer中的每个位代表这个字符串中出现的小写字母?如果只有16个的话那当然可以使用Short。就算字符串中的字母重复了也没关系不会重复占用位。
- 除了使用位表示小写字母之外,我们还需要记录字符串长度,方便后面得出长度乘积。
- 有了位图,直接使用与运算如果等于0肯定就说明不存在重复字符。
那么我们来算下复杂度:
- 时间复杂度为O(n*m+n^2)
- 空间复杂度为O(n)
下面我们直接看代码
代码
public static int maxProduct(String[] words) {
int result = 0;
Map<Integer, Integer> bitMap = new HashMap<>((int) (words.length / 0.75f));
for (String word : words) {
int bit = 0;
for (char c : word.toCharArray()) {
bit |= (1 << (c - 'a'));
}
bitMap.put(bit, Math.max(bitMap.getOrDefault(bit, 0), word.length()));
}
Set<Integer> keySet = bitMap.keySet();
List<Integer> keyList = new ArrayList<>(keySet);
for (int i = 0; i < keyList.size(); i++) {
for (int j = i + 1; j < keyList.size(); j++) {
if ((keyList.get(i) & keyList.get(j)) == 0) {
result = Math.max(result, bitMap.get(keyList.get(i)) * bitMap.get(keyList.get(j)));
}
}
}
return result;
}