【问题标题】:Is there an efficient method to remove elements from a sorted vector in order?有没有一种有效的方法可以按顺序从排序的向量中删除元素?
【发布时间】:2020-11-04 13:28:59
【问题描述】:

考虑一个排序的数字列表A = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9},其中一个元素将在每一步中消除。

假设,我删除 A[4] 项目,我们有 A = {0, 1, 2, 3, 5, 6, 7, 8, 9}
然后我再次删除A[4] 项目,我们有A = {0, 1, 2, 3, 6, 7, 8, 9}
然后A[7] 项目,我们有A = {0, 1, 2, 3, 6, 7, 8}
然后A[0]项目,我们有A = {1, 2, 3, 6, 7, 8}等等。

假设我们事先知道每个 kth 数组中要删除的元素的索引,即 [4, 4, 7, 0...]。此外,注意kth 数组的索引是如何在https://cs.stackexchange.com/q/128352/755 计算的。

如果我要在 C++ 中实现它并且Astd::vector,我需要每次调用A.erase(A.begin()+k),我们将有一个在O(n^2) 中运行的算法。我什至不能在这里使用std::remove,因为元素不会重复。

这里最有效的方法是什么?
还有,是否可以最终打印出按顺序提取的数字序列?

【问题讨论】:

  • 反转要删除的索引的顺序添加到它们:7 + 2、4 + 1、4 + 0,所以你得到9、5、4。如果你希望得到的序列是排序后,按该顺序在每个索引上使用vector::erase。如果不需要对结果进行排序,则将每个索引(9、5、4)与vector::back()resize(size()-1) 交换。
  • 您可以使用 remove_if 函数。它具有大约 O(n) 的复杂度。您可以从这里找到 API cplusplus.com/reference/algorithm/remove_if
  • @TedLyngmo,我不确定我是否理解你的方法。无论如何,您似乎都在使用 vector::erase,如果我要在 4、4、7 之后删除元素 0,我最终会删除 A[0+3] 而不是 A[0]。
  • @Ganesh 解决您的问题print sequence of removed numbers from arrray 总复杂度将是O(n log n)
  • @Ganesh 好的,是的,“是否可以在不删除的情况下找出元素 pk 的索引...”在你的问题中确实有可能,正如我所展示的更多。可以对索引应用一些类似冒泡排序的算法,以降序重新计算它们,以便能够最大限度地减少对erase 的调用,并且必须移动尽可能少的数据。

标签: arrays algorithm c++11 vector stl


【解决方案1】:

这可能是 Captain Obvious 的回答,但如果限制是时间复杂度而不是空间,那么最明显的做法就是按照从第一个向量中移除的顺序填充第二个向量。在第一次遍历向量时,可以以某种方式标记要从原始向量中删除的元素。这将是一个 O(1) 步骤。一旦执行了所有 k 个提取,就可以在向量上调用 erase + remove_if,这将是一个 O(n) 步骤。

所以,代码的整体复杂度应该是 O(n)。

我在此处提供了示例代码以进行说明。请注意,代码中有一些循环只是设置输入数据集,还有一个黑盒算法来确定要提取的元素。

#include <vector>
#include <iostream>
#include <random>
#include <stdexcept>
#include <limits>
#include <algorithm>
#include <functional>
#include <unordered_map>

void populate_vector(std::vector<int>& my_vec)
{
    std::default_random_engine gen;
    std::uniform_int_distribution<int> distribution(1, 100);    //Arbitrarily restricting range to 100

    std::vector<bool> bitmap;
    std::unordered_map<int, bool> num_map;

    auto dice = std::bind(distribution, gen);
    auto capacity = my_vec.capacity();

    while (capacity-- > 0)
    {
        auto ran = 0;
        while (true)
        {
            ran = dice();
            if (num_map.find(ran) == num_map.end())
            {
                break;
            }
        }

        my_vec.emplace_back(ran);
        num_map.emplace(std::make_pair(ran, true));
    }
}

void print_vector(const std::vector<int>& my_vec)
{
    for (const auto& ele : my_vec)
    {
        std::cout << ele << " ";
    }

    std::cout << "\n";
}

int main(int argc, char** argv)
{
    if (argc < 3)
    {
        throw std::invalid_argument("#Elements and #Removal iterations are needed as args\n!");
    }

    auto count = std::stoi(argv[1]);    //Count of elements
    auto k = std::stoi(argv[2]);    //Number of iterations to remove elements
    std::vector<int> my_vec, k_vec;
    std::vector<bool> bitmap;
    my_vec.reserve(count);
    bitmap.reserve(count);

    std::fill(bitmap.begin(), bitmap.end(), false);

    //Setup problem data set
    populate_vector(my_vec);
    print_vector(my_vec);

    auto sentinel = std::numeric_limits<int>::max();

    //Simulating knowledge of kth index with a random selection
    std::default_random_engine gen;
    auto max_idx = my_vec.capacity() - 1;

    std::cout << max_idx << "\n";

    std::uniform_int_distribution<int> distribution(0, max_idx);    //Arbitrarily restricting range to 100

    auto dice = std::bind(distribution, gen);
    auto idx = 0;

    while (k-- > 0)
    {
        //Irrelevant to the complexity of the actual problem
        //This loop is only for the kth element extraction
        while (true)
        {
            idx = dice();
            std::cout << "idx = "<< idx << "\n";
            std::cout << "bitmap[idx]" << bitmap[idx] << "\n";

            if (! bitmap[idx])
            {
                break;
            }
        }

        k_vec.emplace_back(my_vec[idx]);    // O(1)
        my_vec[idx] = sentinel; // O(1)
        bitmap[idx] = true; // O(1)
    }

    my_vec.erase(std::remove_if(my_vec.begin(), my_vec.end(), [sentinel](const int& num){ return (num == sentinel); }), my_vec.end()); //O(n)

    print_vector(my_vec);
    print_vector(k_vec);

    return 0;
}

【讨论】:

    猜你喜欢
    • 2011-02-17
    • 1970-01-01
    • 2013-06-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-11-16
    • 2016-07-07
    相关资源
    最近更新 更多