我正在尝试解决这个问题:
给定字符串数组字,找到length(word [i])* length(word [j])的最大值,其中两个单词不共享公共字母。您可以假设每个单词仅包含小写字母。如果不存在这两个单词,则返回0。
https://leetcode.com/problems/maximum-product-of-word-lengths/
您可以为每个单词创建一个char位图,以检查它们是否共享chars,然后计算最大乘积。
我有两种方法几乎相同,但第一次通过检查,而第二种方法太慢,你能理解为什么吗?
class Solution {
public:
int maxProduct2(vector<string>& words) {
int len = words.size();
int *num = new int[len];
// compute the bit O(n)
for (int i = 0; i < len; i ++) {
int k = 0;
for (int j = 0; j < words[i].length(); j ++) {
k = k | (1 <<(char)(words[i].at(j)));
}
num[i] = k;
}
int c = 0;
// O(n^2)
for (int i = 0; i < len - 1; i ++) {
for (int j = i + 1; j < len; j ++) {
if ((num[i] & num[j]) == 0) { // if no common letters
int x = words[i].length() * words[j].length();
if (x > c) {
c = x;
}
}
}
}
delete []num;
return c;
}
int maxProduct(vector<string>& words) {
vector<int> bitmap(words.size());
for(int i=0;i<words.size();++i) {
int k = 0;
for(int j=0;j<words[i].length();++j) {
k |= 1 << (char)(words[i][j]);
}
bitmap[i] = k;
}
int maxProd = 0;
for(int i=0;i<words.size()-1;++i) {
for(int j=i+1;j<words.size();++j) {
if ( !(bitmap[i] & bitmap[j])) {
int x = words[i].length() * words[j].length();
if ( x > maxProd )
maxProd = x;
}
}
}
return maxProd;
}
};
为什么第二个函数(maxProduct)对于leetcode来说太慢了?
第二种方法重复调用words.size()。如果将其保存在var中,那么它可以正常工作
答案 0 :(得分:1)
由于我的评论证明是正确的,我会将我的评论转化为答案并尝试解释我的想法。
我写了一些简单的代码,在我自己的机器上进行基准测试,每个解决方案有两个循环。唯一的区别是对words.size()的调用是在循环内部而不是在循环外部。第一种解决方案约为13.87秒,而第二种解决方案则为16.65秒。这并不是很大,但它慢了约20%。
尽管vector.size()是一个常量时间操作,但并不意味着它只是检查已经存在于寄存器中的变量。恒定时间仍然可能有很大的差异。当嵌套循环内部加起来时。
可能发生的另一件事(比我更聪明的人可能会插入并让我们知道)是你正在损害你的CPU优化,如分支和流水线。每次到达循环结束时它都必须停止,等待对size()的调用返回,然后根据该返回值检查循环变量。如果cpu可以向前看并猜测j
仍然会小于len
,因为它没有看到len
更改(len
甚至不在循环!)它可以每次做出一个好的分支预测,而不必等待。