两个功能并没有花时间我期望的,因为它们的复杂性很大,任何人都可以解释原因



,所以我解决的问题是在整个整数中找到大多数元素,大小为0<N<10^5,每个元素0<A<10^9。因此,我只需要找出严格显示哪些元素超过N/2次。

我有两种我认为都是正确的解决方案,但它们的行为并不像我对它们的复杂性的理解一样。有人可以向我解释我做错了/误解了什么?

int getMajElement(vector<int> a)
{
std::unordered_map<int, int> countMap;
std::unordered_map<int, int>::iterator it;
for (int i : a)
{
    it = countMap.find(i);
    if (it == countMap.end())
    {
        countMap.insert(std::pair<int, int>(i, 1));
    }
    else
    {
        it->second++;
    }
}
int mostOfNum = 0;
int mostOfNumCount = 0;
for (std::pair<int, int>  pair : countMap)
{
    if (pair.second > mostOfNumCount)
    {
        mostOfNumCount = pair.second;
        mostOfNum = pair.first;
    }
}
if (mostOfNumCount > floor(a.size() / 2))
{
    return mostOfNum;
}
else
{
    return -1;
}
}

从我的理解中,第一个" for(int i:a)"应在o(n)时间内运行,同时查找/递增该值应在o(1)时间内进行hashmap。第二个" for(std ::对对:countmap)"循环也应在o(n)时间内运行,因为我最多遍地迭代。这将是O(n)时间。

此功能需要2.4秒才能运行n = 10^5,每个函数a = rand()%10^9。我确保只花费时间功能,而不是设置初始值。

然后,在相同条件下,下一个需要0.70秒,但我希望第一个会更快。

第二个函数使用递归分隔和纠纷方法来解决问题,应花费O(n log(n))时间。它基本上将列表分为n个单个部分,然后检查左半部分的大多数元素是否与右半部分的大多数元素相同。如果不是,它将扫描列表以查看该部分的总体多数(值> floor((右)/2))并将其传递回去,else -1。

有人可以向我解释是什么原因导致时间差,这只是我犯的实现错误吗?

int get_majority_element(vector<int> &a, int left, int right) {
    if (left == right) return -1;
    if (left + 1 == right) return a[left];
    int mid = left + floor((right - left) / 2);
    int leftMajority = get_majority_element(a, left, mid);
    int rightMajority = get_majority_element(a, mid, right);
    if(leftMajority == rightMajority)
    {
        return leftMajority;
    }
    else if (rightMajority == -1)
    {
        return leftMajority;
    }
    else if (leftMajority == -1)
    {
        return rightMajority;
    }
    else
    {
        int leftCount = 0, rightCount = 0;
        for (int i = left; i < right; i++)
        {
            if (a[i] == leftMajority)
            {
                leftCount++;
            }
            else if (a[i] == rightMajority)
            {
                rightCount++;
            }
        }
        if (leftCount > floor((right - left) / 2))
        {
            return leftMajority;
        }
        else if (rightCount > floor((right - left) / 2))
        {
            return rightMajority;
        }
        else
        {
            return -1;
        }           
    }
    return -1;
}

这太长了评论。

复杂性理论是关于随着数据的大小的增长,单个算法会发生什么。这是n->无穷大的限制。

在比较相同数据大小的两种不同算法方面,它有用得多。为什么?因为开销可以主导计算。例如,气泡排序为o(n^2)。但是(非常)小的数据集,它可以超过"更快"算法的合理实现。

正确的比较将是10^5个元素,然后是10^6,然后是10^7的每个算法的速度。也就是说,给定算法的速度如何增长。

在第一个解决方案中,尝试使用(n个显式)数量的存储桶数量初始化countMap 设置为至少3/4的预期数量的大小元素(鉴于您期望大多数人出现的事实)。

在填写该地图时,您可能会重新进行大量重新设计。unordered_map ::插入警告O(N)的最糟糕的时间复杂性:虽然在所有情况下都不会发生这种情况,但仅发生几次(带有相当大的地图)即可拧紧执行时间。链接说:

仅当新的元素数大于max_load_factor()*bucket_count()。

但是,等等,还有更多!!!
max_load_factor()*bucket_count()大于元素计数时会发生什么?好吧,很可能发生冲突。鉴于任何碰撞都将进入一个以...等待的水桶...在o(1)的时间内进行哈希图。"

如果您有时间,请观看CPPCON14的这一部分以获取更多恐怖故事(无论如何都是周末)。


注意:我并不是说这样做会比第二种方法更快地制作第一个方法;可能是或可能不是这样。我所说的是应用该建议很可能会提高第一种方法的速度。
(我很高兴地说:"我尝试过;这就是在相同的数据上,与和没有明确数量的存储桶")

最新更新