从向量中删除两个相邻元素并将其替换为单个元素

时间:2019-07-09 17:51:05

标签: c++ vector

所以我想从向量中找到两个相邻的元素(last和first是相邻的),以使它们的和最小,然后用一个element = their和替换它们。应当这样做直到剩下一个要素。

我编写了一个函数来查找最小的相邻对并返回较低的索引。然后将所有元素移动到该索引之后的一个位置,并使用a.resize(n-1)。 代码不起作用,我想主要的问题是比较最后和最先。

int index(vector<int> a)
{
int idx=0; int ans=100; int sum=0;
for (int i = 0; i < a.size(); ++i)
{
    sum=a[i]+a[i+1];
    if(sum<ans)
        idx=i;
}
if(a[0]+a[a.size()-1]<ans)
    idx=a.size()-1;
return idx;
}
//in main function
for (int i = 0; i < n-1; ++i)
    {
        int idx=index(a);
        if(idx==a.size()-1)
            {a[0]=a[0]+a[a.size()-1];
                ans+=a[0]+a[a.size()-1];
                a.pop_back();
            }
        else
        {
            a[idx]=a[idx]+a[idx+1];
            ans+=a[idx]+a[idx+1];
            a.erase(a.begin()+idx-1);

        }

2 个答案:

答案 0 :(得分:1)

这是我的解决方法。

由于数组是圆形的,因此数组中的每个元素可能是相邻对中具有最小总和的第一个元素。

因此,考虑索引i处的每个元素,以及索引j(i + 1) % n处的元素对,以找到最小的元素对。 ...其中n是向量中当前元素的数量。 % n将处理数组的环绕和循环性质。当i是最后一个元素(n - 1)时,则j将是第一个元素(0)。

一旦确定了最小对的索引ij,就将两个元素之一替换为和,而将erase替换为另一个。您应用的约定将确定第一个元素和最后一个元素的总和将放置在向量的开头还是结尾。

重复此操作,直到仅剩一个元素为止。

#include <vector>
#include <algorithm>
#include <iostream>
#include <iterator>

// Just a handy function to display the vector.
void print(std::vector<int> const& input)
{
    std::copy(input.begin(), input.end(), std::ostream_iterator<int>(std::cout, " "));
    std::cout << std::endl;
}

int main() {
    std::vector<int> vec{ 3, 1, 4, 1, 5, 9, 2 }; // some example input data

    print(vec);
    while (vec.size() > 1) {
        // Find the smallest pair of adjacent elements.
        size_t min_i = 0;
        size_t min_j = 1;
        int min_sum = vec[0] + vec[1];
        for (size_t i = 1; i < vec.size(); ++i) {
            size_t j = (i + 1) % vec.size();
            int sum = vec[i] + vec[j];
            if (sum < min_sum) {
                min_i = i;
                min_j = j;
                min_sum = sum;
            }
        }
        // Replace element i with the sum.
        vec[min_i] = min_sum;
        // Erase element at j;
        vec.erase(vec.begin() + min_j);

        print(vec);
    }
}

输出:

3 1 4 1 5 9 2
4 4 1 5 9 2
4 5 5 9 2
5 5 9 6
10 9 6
10 15
25

编辑:OP要求显示出错的地方。

对于您的代码,有很多问题和危险的做法。 :(

首先,请记住,如果数组中有[n]个元素,则索引n无效。具有n个元素的数组的有效索引为0n-1(含)。因此,当[i]缓冲区溢出错误时访问[i+1]i == n-1,因为您正在访问元素n-1(最后一个)和{{1} },最后一个。

您的计算最小总和的代码不正确,因为更新n-1 + 1(应该是本地更新)而不是sum。编写较小的函数,并为这些函数编写单元测试。如果编写了一个函数来计算数组对的最小值,那么即使最基本的单元测试,它也会失败。您编写的代码无法计算最小值。

给出一个包含至少一个元素的数组,找到最小值的索引,其索引通常如下所示:

ans

int min_val = a[0]; int min_index = 0; for (int i = 1; i < n; ++i) { if (a[i] < min_val) { min_val = a[i]; min_index = i; } } 不是适当的初始最小值(如果这就是您想要的初始值)。像100这样的值更好。 MAX_INT对于现代C ++还是更好。

您在一个循环中递增std::numerical_limits<int>::max(),该循环保留了先前循环中先前用法的值。另外,此后程序中不再使用ans。我建议您明智地将限制范围尽可能地应用于局部变量。

通过使用逻辑检查来编写重复代码,可以特别地包装好代码,从而增加了引入错误的机会,而应该使用模数运算符将代码路径提炼为单个路径。可以处理环绕式和名义上的相邻情况。

最后,您的所有算法所要做的就是计算数组的总和并将其存储在单个元素中。与直接和计算相比,使用ans一次删除一个元素的方法会导致性能下降。我很荣幸您的要求这样做,因为您没有透露您的“理由”,并且在这一点上,我仍然认为这是毫无道理和可疑的,除非这只是一种学习练习。

答案 1 :(得分:0)

您可以使用以下算法:

  • 分配要替换为新值的元素之一。
  • 擦除另一个。