我完成了leetcode algorithm的两个版本,我想知道我的复杂性分析是否正确,即使ms的在线提交时间没有准确显示。目标是将数字向量作为引用,如果它包含重复值则返回true,否则返回false。
两种最直观的方法是:
1。)对矢量进行排序并对倒数第二个进行扫描,然后查看是否有相邻的元素是相同的,如果是,则返回true。
2.。)使用哈希表并插入值,如果表中已存在某个键,则返回true。
我首先完成了第一个版本,它很快,但是看看排序例程将如何O(nlog(n))
和哈希表插入& map.count()
s would制作第二个版本O(log(n) + N) = O(N)
我认为使用非常大的数据集时,散列版本会更快。
在在线评判中,我被证明是错误的,但我认为他们没有使用足够大的数据集来抵消std::map
开销。所以我运行了很多测试,重复填充0到10000之间的向量,递增2,在0到20000之间添加随机值。我将输出传输到csv文件并将其绘制在linux上,这是我得到的图像
the provided image在O(N)
和O(nlog(n))
算法之间是否真正向我显示了区别?我只是想确保我的复杂性分析是正确的吗?
bool containsDuplicate(vector<int>& nums) {
if(nums.size() < 2) return false;
sort(nums.begin(), nums.end());
for(int i = 0; i < nums.size()-1; ++i) {
if(nums[i] == nums[i+1]) return true;
}
return false;
}
// Slightly slower in small cases because of data structure overhead I presume
bool containsDuplicateWithHashing(vector<int>& nums) {
map<int, int> map;
for (int i = 0; i < nums.size(); ++i) {
if(map.count(nums[i])) return true;
map.insert({nums[i], i});
}
return false;
}
答案 0 :(得分:2)
std::map
is sorted, and involves O(log n)
cost for each insertion and lookup,所以&#34;没有重复的总费用&#34; case(或#34;在#vector结束时的第一个副本&#34; case)将具有与排序和扫描类似的大O:O(n log n)
;它通常在内存中碎片化,因此开销很容易高于优化std::sort
的开销。
如果重复是常见的,它会显得更快;如果您通常在前10个元素中找到重复项,那么输入是否包含10,000个元素并不重要,因为map
在您复制并删除之前没有时间增长。它只是一个只有在成功时才能正常运行的测试对于一般用法来说不是一个很好的测试(如果重复是常见的,测试看起来有点傻);你希望在包含重复的内容中都有良好的表现,并且不包含重复的案例。
如果您希望将方法与有意义的不同算法复杂度进行比较,请尝试使用std::unordered_set
替换基于地图的解决方案(insert
返回密钥是否已存在,以便您减少工作从一次查找,然后一次插入到每个循环上的一次组合插入和查找),其中O(1)
插入和查找的平均情况为O(n)
重复检查复杂性。
仅供参考,另一种方法是O(n log n)
,但使用类似排序的策略,在早期找到重复项时快捷方式,就是使用std::make_heap
(O(n)
工作堆栈),然后从堆中重复pop_heap
(每个pop O(log n)
)并与堆.front()
进行比较;如果您弹出的值和前面的值相同,则表示您已复制并可立即退出。您还可以使用priority_queue
适配器将其简化为单个容器,而不是在std::vector
等上手动使用实用程序功能。