给定一个字符串数组 words
,找到 length(word[i]) * length(word[j])
的最大值,并且这两个单词不含有公共字母。你可以认为每个单词只包含小写字母。如果不存在这样的两个单词,返回 0。
示例 1:
输入:["abcw","baz","foo","bar","xtfn","abcdef"]
输出:16 解释: 这两个单词为
"abcw", "xtfn"
示例 2:
输入:["a","ab","abc","d","cd","bcd","abcd"]
输出:4 解释:
这两个单词为"ab", "cd"
示例 3:
输入:["a","aa","aaa","aaaa"]
输出:0 解释: 不存在这样的两个单词。
提示:
2 <= words.length <= 1000
1 <= words[i].length <= 1000
words[i]
仅包含小写字母
思路一:最暴力的算法很容易想到是枚举两个串,再遍历两个串看是否有重复字符,复杂度为O(n^2*L)。
思路二:我们注意到数据规模中,n<=1000,L<=1000,因此需要针对n^2或者L优化。直觉上,貌似串的枚举是避免不了的,亦或是很难想到优化,那么我们能不能考虑如何快速判断两个串是否有重复字符呢?
方案1:我们先使用标记数组mark[i]=true表示在字符串A中,已经包含字符 'a' + i,此时再遍历字符串B,如果发现字符串B含有的某个字符的标记为true,那么表明A、B存在相同字符
方案2:由于要看的是是否有重复字符,与字符在哪里无关,因此我们可以事先将字符串内的所有字符排序,然后使用双指针进行判定,即
当A[p] < B[q]时,令 p++
当A[p] > B[q]时,令 q++
当A[p]==B[q]时,找到了重复字符
否则,p、q任何一个指针超出了字符串范围,则不含有重复字符
方案2可能可以加速含有重复字符串的判定,但无法加速不含有重复字符的字符串判定
方案3:减少重复计算的思路就是如何利用之前做的计算中所包含的信息,例如,如果A、B之间存在某个相同字符x,且B与C之间存在某个相同字符x,此时就可以根据传递性知道,A、C之间一定有重复字符x,但是这个方案需要考虑的细节很多,编码较为复杂~~
方案4:重新思考方案1,这种哈希的思想是很好的,但是我们用了一个长度为26的数组来存储哈希状态,这就是局限。那么如何根据两个串各自的哈希值判断两个字符串是否有重复?如果能想到位运算,我们将字符串中含有的字符映射为一个26位的二进制数,那么当(hash_A & hash_B) != 0 的时候,表明串A、B存在重复字符。
class Solution {
public:
int string_hash(string str){
int res = 0;
for(int i = str.size() - 1; i >= 0; -- i){
res |= 1 << (str[i] - 'a');
}
return res;
}
int maxProduct(vector<string>& words) {
vector<int> hash_vec, string_len;
int hash_value, ans = 0, i, j, n = words.size();
for(string word: words){
hash_value = string_hash(word);
hash_vec.push_back(hash_value);
string_len.push_back(word.length());
}
for(i = 0; i < n; ++ i){
for(j = i + 1; j < n; ++ j){
if(hash_vec[i] & hash_vec[j]){
continue;
}
ans = max(ans, string_len[i] * string_len[j]);
}
}
return ans;
}
};