【问题标题】:How to erase all elements from a vector except for the largest in a specific range?如何从向量中删除除特定范围内最大的元素之外的所有元素?
【发布时间】:2017-09-02 00:48:27
【问题描述】:

假设我有以下向量:

向量是成对的向量,我们根据第一个元素进行比较。

[(1,0),(0,1),(3,2),(6,3),(2,4),(4,5),(7,6),(5,7)]

我想删除特定范围内的所有元素,除了最大的。

例如,如果范围是 $l = 2$ 和 $r = 5$,那么输出:

[(1,0),(0,1),(6,3),(7,6),(5,7)]

现在如果我们对 $l = 1$, $r = 4$ 的输出数组再次执行此操作,则输出:

[(1,0),(7,6)]

我找到了this,我认为它在这里很有用,但我不知道如何让它对成对起作用。

这是我的尝试:

int main(int argc, char const *argv[]) {
    int N;
    cin >> N;
    vector< pair<int,int> > vector_of_pairs(N);

    for (int i = 0; i < N; i++) {
        int input;
        cin >> input;
        vector_of_pairs[i] = make_pair(input, i);
    }

    int l, r;
    cin >> l >> r;

    int max_in_range = vector_of_pairs[l].first;

    for (int i = l+1; i <= r; i++) {
        if (vector_of_pairs[i].first > max_in_range) {
            max_in_range = vector_of_pairs[i].first;
        }
    }

    for (int i = l; i <= r; i++) {
        if (vector_of_pairs[i].first != max_in_range) {
            vector_of_pairs.erase(vector_of_pairs.begin() + i);
        }
    }

    printf("[");
    for(int i = 0; i < vector_of_pairs.size(); i++) {
        printf("(%d,%d)", vector_of_pairs[i].first, vector_of_pairs[i].second);
    }
    printf("]\n");
}

对于以下输入:

8              
1 0 5 6 2 3 7 4 
1 3

这是输出:

[(1,0)(5,2)(6,3)(3,5)(7,6)(4,7)]

但应该是的

[(1,0)(6,3)(3,5)(7,6)(4,7)]

另外,对于某些输入,我会遇到段错误,那么我该如何防范呢?

【问题讨论】:

  • 请在程序本身中发布/硬编码输入。无需继续在键盘上输入。
  • 您能否详细说明@PaulMcKenzie?你的意思是我应该在代码中包含输入/输出示例?
  • @PaulMcKenzie std::vector> 输入 { std::make_pair( 1 , 0 ) , std::make_pair( 0 , 1 ) , std:: make_pair( 3 , 2 ) , std::make_pair( 6 , 3 ) , std::make_pair( 2 , 4 ) , std::make_pair( 4 , 5 ) , std::make_pair( 7 , 6 ) , std:: make_pair( 5 , 7 ) };
  • @user6005857:喜欢this
  • 当你擦除时,未来的begin() + i 将不是你所期望的。

标签: c++ vector


【解决方案1】:

Erase remove idiom 在救援中:

auto begin = v.begin() + l;
auto end = v.begin() + r + 1;
auto max_value = *std::max_element(begin, end);
v.erase(std::remove_if(begin, end,
                       [&](const auto& p) {return p.first != max_value.first; }),
        end);

Demo

【讨论】:

  • -.- 你领先我一秒
  • 这是一个了不起的解决方案!但我在[&amp;] 上收到编译器错误,在auto 上收到警告。有可能解决这个问题吗?
  • @user6005857 你在使用C++ 11 兼容的编译器吗?
  • 可能值得注意的是,此解决方案不适用于所有容器,除非它们更改了列表迭代器的工作方式
  • @deW1:OP 使用std::vectorv.begin() + x 确实可能被 std::next(v.begin(), x) 取代。
【解决方案2】:

可能你想要这个

#include <iostream>
#include <vector>
using namespace std;


int main(int argc, char const *argv[]) {
    int N;
    cin >> N;
    vector< pair<int,int> > vector_of_pairs(N);

    for (int i = 0; i < N; i++) {
        int input;
        cin >> input;
        vector_of_pairs[i] = make_pair(input, i);
    }

    int l, r;
    cin >> l >> r;

    int max_in_range = vector_of_pairs[l].first;

    for (int i = l+1; i <= r; i++) {
        if (vector_of_pairs[i].first > max_in_range) {
            max_in_range = vector_of_pairs[i].first;
        }
    }
    int p=l;
    for (int i = l; i <= r;i++ ) {
        if (vector_of_pairs[p].first != max_in_range) {
            vector_of_pairs.erase(vector_of_pairs.begin()+p);
        }
        else p++; 
    }

    printf("[");
    for(int i = 0; i < vector_of_pairs.size(); i++) {
        printf("(%d,%d)", vector_of_pairs[i].first, vector_of_pairs[i].second);
    }
    printf("]\n");
}

得到正确的输出:

[(1,0)(6,3)(2,4)(3,5)(7,6)(4,7)]

解释:当你删除向量中的一个项目时,在被删除元素之后出现的项目的索引减少了 1。因此在从 l 到 r 的第 i 个循环中,你不应该删除 vec.begin ()+i 元素,改为删除 vec.begin()+l 项直到找到最大元素,找到最大元素后删除 vec.begin()+l+1 元素。

希望对你有帮助。

【讨论】:

  • 如果有多个最大值,您可以用计数器替换done
  • C-ish。根据特定标准从容器中擦除,可以使用各种算法更简洁地完成,主要是std::remove_iferase
  • 我忘了说,所有数字都是唯一的,不能有多个最大值。但是,这个答案我得到了错误的输出。
  • 现在可以试试吗?
  • 你不认为输入 l=1, r=3 输出应该是 [(1,0)(6,3)(2,4)(3,5)(7,6)( 4,7)]
【解决方案3】:

如果您不需要稳定的算法,您可以简单地对向量进行排序,在 begin - end 中获取 l 的迭代器,在 l - end 中获取 r 的迭代器,然后删除除最后一个元素之外的所有元素都找到了迭代器。

#include <algorithm>
template<class V, class T>
void remove_range_but_max(V& vop, T const& l, T const& r)
{
    std::sort(vop.begin(), vop.end());
    auto lo = std::lower_bound(vop.begin(), vop.end(), l);
    auto hi = std::lower_bound(lo, vop.end(), r);
    if(hi != lo) --hi;
    vop.erase(lo, hi);
}

可以这样使用:

std::vector< std::pair< int , int > > input { 
    std::make_pair( 1 , 0 ) , std::make_pair( 0 , 1 ) , 
    std::make_pair( 3 , 2 ) , std::make_pair( 6 , 3 ) , 
    std::make_pair( 2 , 4 ) , std::make_pair( 4 , 5 ) , 
    std::make_pair( 7 , 6 ) , std::make_pair( 5 , 7 ) };
/* remove all pairs in range [(2,0), (6,0)) */
remove_range_but_max(input, std::make_pair(2,0), std::make_pair(6,0));
for(auto&& p : input) std::cout << p.first << ", " << p.second << "\n";

打印:

0, 1
1, 0
5, 7
6, 3
7, 6

【讨论】:

    【解决方案4】:

    快速而低俗的方式:

    std::sort(vector_of_pairs.begin(), vector_of_pairs.end());
    vector_of_pairs.resize(1);
    

    只需确保为 sort 提供适当的函数,以使最大的元素被推送到列表的第一个。

    让我为你拼写出来:

    #include <iostream>
    #include <vector>
    #include <algorithm>
    
    using namespace std;
    
    bool i_said_to_do_this(const pair<int, int> &lhs, const pair<int, int> &rhs) {
      return lhs.first > rhs.first;
    }
    
    int main(int argc, char const *argv[]) {
    
        int pairs[][2] = {{1,0},{0,1},{3,2},{6,3},{2,4},{4,5},{7,6},{5,7}}; 
        vector< pair<int,int> > vector_of_pairs(8);
    
        for (int i{0}; i < 8; i++) {
          vector_of_pairs[i] = make_pair(pairs[i][0], pairs[i][1]);
        }
    
        std::sort(vector_of_pairs.begin(), vector_of_pairs.end(), i_said_to_do_this);
        vector_of_pairs.erase(vector_of_pairs.begin() + 1, vector_of_pairs.end());
    
        cout << "(" << vector_of_pairs[0].first << ", " << vector_of_pairs[0].second << ")" << endl;
    }
    

    【讨论】:

    • 这给出了所有输入的输出 [(0,1)]。
    • @user6005857 我的回答是正确的,您似乎没有注意到我在代码示例之后指出的部分。默认情况下,你会得到最小值,你必须改变排序才能得到你想要的结果。
    • @Aumnayan:OP 希望保留一个范围的元素并丢弃该范围的其他元素。并且范围可能小于整个向量。
    • @Jarod42 谢谢我错过了这个并更新了我的答案。只需将 begin() 和 end() 调用替换为您要操作的迭代器范围。
    • 然后你还要处理tie
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-02-08
    • 1970-01-01
    • 1970-01-01
    • 2016-02-12
    相关资源
    最近更新 更多