几乎相同的代码运行得慢得多

时间:2016-04-28 13:03:33

标签: c++

我正在尝试解决这个问题:

  

给定字符串数组字,找到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中,那么它可以正常工作

1 个答案:

答案 0 :(得分:1)

由于我的评论证明是正确的,我会将我的评论转化为答案并尝试解释我的想法。

我写了一些简单的代码,在我自己的机器上进行基准测试,每个解决方案有两个循环。唯一的区别是对words.size()的调用是在循环内部而不是在循环外部。第一种解决方案约为13.87秒,而第二种解决方案则为16.65秒。这并不是很大,但它慢了约20%。

尽管vector.size()是一个常量时间操作,但并不意味着它只是检查已经存在于寄存器中的变量。恒定时间仍然可能有很大的差异。当嵌套循环内部加起来时。

可能发生的另一件事(比我更聪明的人可能会插入并让我们知道)是你正在损害你的CPU优化,如分支和流水线。每次到达循环结束时它都必须停止,等待对size()的调用返回,然后根据该返回值检查循环变量。如果cpu可以向前看并猜测j仍然会小于len,因为它没有看到len更改(len甚至不在循环!)它可以每次做出一个好的分支预测,而不必等待。