我正在 LeetCode 上解决一个问题,但还没有人能够解释我的问题。
问题是这样的:
给定一个任意的赎金票据字符串和另一个包含来自所有杂志的字母的字符串,编写一个函数,如果赎金票据可以从杂志中构造出来,该函数将返回 true ;否则,它将返回 false。
杂志字符串中的每个字母只能在您的赎金记录中使用一次。
注意: 您可能会假设这两个字符串都只包含小写字母。
canConstruct("a", "b") -> false
canConstruct("aa", "ab") -> false
canConstruct("aa", "aab") -> true
我的代码(耗时 32 毫秒):
class Solution {
public:
bool canConstruct(string ransomNote, string magazine) {
if(ransomNote.size() > magazine.size()) return false;
unordered_map<char, int> m;
for(int i = 0; i < magazine.size(); i++)
m[magazine[i]]++;
for(int i = 0; i < ransomNote.size(); i++)
{
if(m[ransomNote[i]] <= 0) return false;
m[ransomNote[i]]--;
}
return true;
}
};
代码(我不知道为什么更快 - 需要 19 毫秒):
bool canConstruct(string ransomNote, string magazine) {
int lettersLeft = ransomNote.size(); // Remaining # of letters to be found in magazine
int arr[26] = {0};
for (int j = 0; j < ransomNote.size(); j++) {
arr[ransomNote[j] - 'a']++; // letter - 'a' gives a value of 0 - 25 for each lower case letter a-z
}
int i = 0;
while (i < magazine.size() && lettersLeft > 0) {
if (arr[magazine[i] - 'a'] > 0) {
arr[magazine[i] - 'a']--;
lettersLeft--;
}
i++;
}
if (lettersLeft == 0) {
return true;
} else {
return false;
}
}
这两者具有相同的复杂度并使用相同的结构来解决问题,但我不明白为什么一个花费的时间几乎是另一个的两倍。查询 vector 的时间是 O(1),但它对于 unordered_map 是相同的。向其中任何一个添加条目/ key 也是如此。
请问有人能解释一下为什么运行时间变化如此之大吗?
最佳答案
首先要注意的是,虽然查询unordered_map
的平均时间是常数,但最坏的情况不是O(1)
。如你所见here它实际上上升到O(N)
的数量级,N
表示容器的大小。
其次,由于 vector
分配内存的连续部分,因此即使在最坏的情况下,访问该内存的效率也很高,而且实际上是常量。 (即简单的指针算法,而不是计算更复杂的散列函数的结果)还有可能涉及不同级别的顺序内存缓存(即取决于您的代码运行的平台)这可能与使用 unordered_map
的代码相比,使用 vector
的代码执行速度更快。
本质上,就复杂度而言,vector
的最坏情况下的性能比unordered_map
的效率更高。最重要的是,大多数硬件系统都提供诸如缓存之类的功能,这使 vector
的使用具有更大的优势。 (即 O(1)
操作中较小的常数因子)
关于c++ - 为什么 vector 比 unordered_map 快?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55451825/