c++ 子表项最大值

sqserrrh  于 2023-01-28  发布在  其他
关注(0)|答案(1)|浏览(117)

我正在寻找一个最佳的方法来找到子列表项在列表中的最大值。
下面是我的O(n.m)实现:

vector<int> movMax(const vector<int>& v, int span)
{
    span /= 2;

    vector<int> ret = v;
    for (int i = 0; i < (int)v.size(); ++i)
    {
        for (int j = std::max(0, i - span); j < std::min((int)v.size(), i + span + 1); j++)
        {
            ret[i] = std::max(ret[i], v[j]);
        }
    }
    return ret;
}

int main()
{
    vector<int> v = { 4, 3, 3, 7, 2, 5, 1, 2 };

    v = movMax(v, 3);
    for (int x : v) cout << x << ' '; // 4 4 7 7 7 5 5 2
}
63lcw9qa

63lcw9qa1#

这里有一个O(N log M)的版本,其中N是输入的大小,M是窗口。
我们按顺序跟踪窗口中的值,因此添加或删除它们是O(log M),并且我们对v的每个元素都这样做。

std::vector<int> movMax(const std::vector<int>& v, int window)
{
    int mid = window / 2;
    int size = v.size();
    
    std::vector<int> result;
    result.reserve(size);
    std::multiset<int> working_set;
    
    for (int i = -mid; i < size + mid; ++i) 
    {    
        if (i + mid < size) working_set.insert(v.at(i + mid));
        if (i >= 0 && i < size) result.push_back(*working_set.rbegin());
        if (i - mid >= 0) working_set.erase(working_set.find(v.at(i - mid)));
    }
    
    return result;
}

See it on coliru
如果允许窗口为偶数,则需要考虑它倾向于哪一侧。
您可以使用widenarrow,而不是定义一个mid

int wide = window / 2;
int narrow = window - wide - 1;

假设窗口应向前扩展更多:

for (int i = -narrow; i < size + wide; ++i) 
{    
    if (i + narrow < size) working_set.insert(v.at(i + narrow));
    if (i >= 0 && i < size) result.push_back(*working_set.rbegin());
    if (i - wide >= 0) working_set.erase(working_set.find(v.at(i - wide)));
}

假设窗口应向后扩展更多:

for (int i = -wide; i < size + narrow; ++i) 
{    
    if (i + wide < size) working_set.insert(v.at(i + wide));
    if (i >= 0 && i < size) result.push_back(*working_set.rbegin());
    if (i - narrow >= 0) working_set.erase(working_set.find(v.at(i - narrow)));
}

With tests on godbolt

相关问题