【问题标题】:Why erase+remove is more efficient than remove为什么擦除+删除比删除更有效
【发布时间】:2020-01-09 02:23:26
【问题描述】:

我正在编写 C++ 来解决 Leetcode 中的这个问题:https://leetcode.com/problems/remove-element/

给定一个数组 nums 和一个值 val,删除它的所有实例 就地取值并返回新的长度。

不要为另一个数组分配额外的空间,你必须这样做 使用 O(1) 额外内存就地修改输入数组。

元素的顺序可以改变。你离开什么都没关系 超出新长度。

示例 1:

给定 nums = [3,2,2,3], val = 3,

您的函数应返回长度 = 2,前两个元素为 nums 为 2。

您在返回的长度之外留下什么并不重要。

我有两个解决方案:

解决方案 A:

int removeElement(vector<int>& nums, int val) {
    nums.erase(remove(begin(nums), end(nums), val), end(nums));
    return nums.size();
}

解决方案 B:

int removeElement(vector<int>& nums, int val) {
    auto it = std::remove(nums.begin(), nums.end(), val);
    return it - nums.begin();
}

在我看来,解决方案 B 应该比解决方案 A 更快。然而,结果却相反:

解决方案 A 花费了 0 毫秒,而解决方案 B 花费了 4 毫秒。

我不知道为什么remove + erase 比remove 快。

【问题讨论】:

  • 还要注意两个sn-ps的代码做的事情非常不同。
  • 那么差异可能是因为两个函数的行为不同。
  • 0ms 和 4ms 是足够小的值,任何差异都几乎没有意义。它们很容易受到机器上运行的其他进程等因素的影响。
  • 编译器可能知道erase-remove idiom,可以更好地优化它。此外,对于 std::vector 擦除 n 的最后一个元素是单个算术运算(对于原始类型)。

标签: c++ algorithm performance stl


【解决方案1】:

对于一般可破坏类型的向量(int 就是这样一种类型),erase(it, end()) 通常只是一个大小成员(或指针成员,取决于实现策略)的递减,几乎不需要时间。 4毫秒是一个非常非常小的差异。它很容易由机器的状态引起。而且我不会期望如此小的差异可以重现。

如果您想真正从向量中删除元素,请使用第一个版本。如果您真的想做std::remove 所做的事情(您可能不这样做),请使用第二个版本。性能不是这里的问题。

【讨论】:

  • 另外,对于第二个版本,参数最好是std::span&lt;int&gt;。
  • @Deduplicator 是的,这样会更好。
  • 实际上,对于向量,erase(it, end()) 需要减少整数(大小、指针等)成员变量和调用析构函数。对于ints,析构函数什么都不做(或者不存在;你的选择)并且不生成任何代码。
  • @MarshallClow 是的,这很简单。已更新。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-10-22
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多