C++ 为什么尽管有相同的算法和数据结构,另一个解决方案的效率却提高了10倍?
我在leetcode上找到了一段代码,并将其与我的解决方案进行了比较 问题链接: Leetcode解决方案:(16毫秒和10.2 MB)C++ 为什么尽管有相同的算法和数据结构,另一个解决方案的效率却提高了10倍?,c++,algorithm,data-structures,stack,C++,Algorithm,Data Structures,Stack,我在leetcode上找到了一段代码,并将其与我的解决方案进行了比较 问题链接: Leetcode解决方案:(16毫秒和10.2 MB) string removeDuplicates1(string s,int k){ 向量st; 字符串res; 用于(自动通道:s){ if(st.empty()| | st.back().first!=ch)st.push_-back({ch,0}); 如果(++st.back().second==k)st.pop_back(); } for(auto&p:
string removeDuplicates1(string s,int k){
向量st;
字符串res;
用于(自动通道:s){
if(st.empty()| | st.back().first!=ch)st.push_-back({ch,0});
如果(++st.back().second==k)st.pop_back();
}
for(auto&p:st)res+=字符串(p.second,p.first);
返回res;
}
我的解决方案:(32毫秒和132.5 MB)
string removeDuplicates2(string str,int k){
如果(k==1)
返回“”;
向量S;
对于(int i=0;i将@Johannes Schaub的评论扩展为答案,问题可能就在这里:
for(auto& i : S) {
result = result + string(i.second, i.first);
}
for
循环中的表达式表示执行以下操作:
计算赋值语句的右侧。为此,创建一个全新的字符串,该字符串由克隆result
并附加string(i.second,i.first)
形成
用这样形成的新字符串覆盖结果
换句话说,每次通过此循环时,您都会复制到目前为止创建的整个字符串(可能非常大),然后再添加几个字符,然后删除旧字符串并替换为新字符串。这会占用大量内存并花费大量时间
另一方面,考虑解决方案中的循环:
for (auto& p : st) {
res += string(p.second, p.first);
}
这使用了+=
操作符,该操作符表示“通过将字符串(p.second,p.first)
固定到字符串的末尾来扩展现有的字符串res
。”这不涉及制作任何副本*,因此它使用的内存和时间更少
一般来说,当您可以编写lhs+=rhs
时,请避免编写lhs=lhs+rhs
,因为前一条语句会复制,而后一条语句则不会
*在内部,字符串可能需要调整其内部缓冲区的大小以获得容纳新字符的更多空间,因此它可能需要复制内容。但是,用于执行此操作的策略过度分配了空间,因此复制所花费的总工作量在序列的最终大小中是线性的。+=rvalue比=lvalue+rvalue更有效。这是e我一直在寻找的答案。现在重新提交确认。谢谢!还要注意的是,对于+=
,现有字符串只有在组合字符串超过可用容量时才会分配新缓冲区。只有在需要分配新缓冲区时,它才会复制现有字符串,因此很少会支付开销。嗯,我想我知道I’我学到了一个好习惯。
for(auto& i : S) {
result = result + string(i.second, i.first);
}
for (auto& p : st) {
res += string(p.second, p.first);
}