遇到零时划分数组

Posted

技术标签:

【中文标题】遇到零时划分数组【英文标题】:divide array when encountering zeroes 【发布时间】:2021-03-11 19:14:22 【问题描述】:

我想将一个数组分成多个(或一个,可能是零个)数组,如下例所示:

array = [0 1 1 2 3 4 0 3 0 3 3 0 5 6 7] -> array1 = [1 1 2 3 4] array2 = [3] array3 = [3 3] array4 = [5 6 7 ]

我的幼稚方法是首先从左右删除零,然后继续使用两个迭代器来查找每个子数组的开始和结束,并使用向量构造函数构建子数组并将它们传递给函数。但我知道我的方法是幼稚且低效的,因此我希望能就如何更有效地解决这一问题提出一些建议。

非常感谢大家!

这也是我的方法的代码(a 是母数组):

for(int i = 0; i < a.size(); i++)
        if(a[i] != 0)
            break;
        a.erase(a.begin() + i);    
    

    for(int i = a.size() - 1; i >= 0; i--)
        if(a[i] != 0)
            break;
        a.erase(a.begin() + i);    
    

    auto begin = a.begin();
    auto end = a.begin() + 1;
    for (int i = 0; i < a.size(); i++)
        if(a[i] == 0)
            vector<int> temp(begin, end);
            color(temp);
            begin = end + 1;
            end = begin + 1;
        
        else end++;
     

【问题讨论】:

请添加语言标签 您可以创建一个std::vector&lt;std::vector&lt;int&gt;&gt; result; 并(多次)使用像std::find 这样的算法,如果您允许这样做,无需从来源。 【参考方案1】:

解决此问题的方法之一是创建一个包含所有零元素索引的辅助数组(在实现中使用const_iterator 而不是索引)。这个问题可以在不创建辅助数组的情况下解决,但这样做的好处是可以提前知道要创建多少个子数组。做法如下,

迭代输入数组并将零元素的索引放入辅助数组中, InputArray = [0, 1, 1, 2, 3, 4, 0, 3, 0, 3, 3, 0, 5, 6, 7] 数组包含零个元素索引 = [0, 6, 8, 11]

正如您在上面看到的,有四个分隔符(零索引条目)将输入数组划分为 3 子数组,最后一个零位于索引 11 处,这不是输入数组的最后一个元素,这就是为什么多了一个子数组将创建数组,因此总子数组 = 4 其他详细信息请参阅代码,

#include <iostream>

#include <vector>

#include <iterator>
#include <algorithm>

using std::cout;

std::vector<std::vector<int>> splitAtZero(const std::vector<int>& arr)

    std::vector<std::vector<int>::const_iterator> divider;
    divider.reserve(std::max<std::size_t>(arr.size() / 4, 2));

    for(std::vector<int>::const_iterator it = arr.cbegin(), endIt = arr.cend(); endIt != it; ++it)

        if(0 == *it)
            divider.push_back(it);
        
    

    if(divider.empty())
        return arr;
    

    if(arr.size() == divider.size())
        return ;
    

    std::size_t numOfSubArray = (divider.size() - 1) + (arr.cbegin() != divider.front() ? 1 : 0) +
            (arr.cend() != divider.back() ? 1 : 0);

    std::vector<std::vector<int>> subArr;
    subArr.reserve(numOfSubArray);

    std::vector<int>::const_iterator it = arr.cbegin();

    for(std::vector<int>::const_iterator divderIt : divider)

        if(divderIt - it > 0)

            subArr.emplace_back(it, divderIt);
        

        it = divderIt + 1;
    

    if(arr.cend() != it)

        subArr.emplace_back(it, arr.cend());
    

    return subArr;


int main()

    std::string comma("");

    for(std::vector<int>& subArr : splitAtZero(0, 1, 1, 2, 3, 4, 0, 3, 0, 3, 3, 0, 5, 6, 7))

        cout<< comma<< "[";

        std::copy(subArr.cbegin(), subArr.cbegin() + (subArr.size() - 1), std::ostream_iterator<int>(cout, ", "));

        cout<< subArr.back()<< "]";
        comma = ", ";
    

    cout<< '\n';

输出:[1, 1, 2, 3, 4], [3], [3, 3], [5, 6, 7]

【讨论】:

【参考方案2】:

在我建议的以下方法中,您可以通过单次顺序扫描检索子数组,而无需在开头或结尾排除零:

std::vector<std::vector<int>> arrays;
std::vector<int> currentArray;
for (int i = 0; i < a.size; i++)

    if (a[i] == 0 || i == a.size - 1)
    
        if (currentArray.size() != 0)
        
            arrays.push_back(currentArray);
            currentArray.clear();
        
    
    else
    
        currentArray.push_back(a[i]);
    

【讨论】:

您可能希望将最后一个 currentArray 推送到 arrays

以上是关于遇到零时划分数组的主要内容,如果未能解决你的问题,请参考以下文章

分数等级划分

分数等级划分

划分算法

格式化二维数组中输入的数据

划分数 (DP)

随机产生30到整数真分数四则运算