从左到右遍历数组并收集尽可能多的数字

如何解决从左到右遍历数组并收集尽可能多的数字

CSES 问题 (https://cses.fi/problemset/task/2216/)。

给定一个数组,其中包含 1…n 之间的每个数字恰好一次。您的任务是按递增顺序收集从 1 到 n 的数字。 在每一轮中,您从左到右遍历数组并收集尽可能多的数字。总回合数是多少? 约束条件:1≤n≤2⋅10^5

这是我的 C++ 代码

int n,res=0;
cin>>n;
int arr[n];
set <int,greater <int>> lastEl;
for(int i=0; i<n; i++) {
    cin>>arr[i];
    auto it=lastEl.lower_bound(arr[i]);
    if(it==lastEl.end()) res++;
    else lastEl.erase(*it);
    lastEl.insert(arr[i]);
}
cout<<res;

我遍历了一次数组。如果元素 arr[i] 小于之前的所有元素,那么我“打开”一个新序列,并将该元素保存为该序列中的最后一个元素。我将已打开序列的最后一个元素存储在集合中。如果 arr[i] 小于前面的一些元素,那么我取已经存在的具有最大最后一个元素(但小于 arr[i])的序列,并用 arr[i] 替换该序列的最后一个元素。 唉,它只适用于给定的三个测试中的两个测试,而对于第三个测试,输出比它应该的要少得多。我做错了什么?

解决方法

让我详细解释一下我的思考过程,以便您下次遇到相同类型的问题时更轻松。

首先,我在面对此类问题时经常犯的一个错误是模拟过程的冲动。问题陈述中提到的“模拟过程”是什么意思?该问题提到进行一轮以最大化按特定顺序增加的数字的集合。所以,你从 1 开始,找到它并看到下一个数字 2 不在它之外,即 2 不能与 1 在同一轮并形成递增的序列。因此,我们需要对 2 进行另一轮。现在我们发现,23 都可以在同一轮中收集,因为我们从左向右移动并按递增顺序获取数字。但是我们不能取 4,因为它在 2 之前开始。最后,对于 45,我们需要另一轮。这样一共进行了三轮。

现在,如果您以这种方式模拟过程,问题将变得非常容易解决。在第一轮中,您查找以 1 开头的构成递增序列的数字。在开始第二轮之前删除这些数字。你继续这样,直到你用完所有的数字。

但是模拟这个过程会导致时间复杂度无法通过问题陈述中提到的约束。所以,我们需要想出另一种方法,在不模拟整个过程的情况下给出相同的输出。

请注意,数字的位置在这里至关重要。为什么我们需要对 2 进行另一轮?因为它出现在 1 之前。我们不需要对 3 进行另一轮,因为它在 2 之后。同样,我们需要对 4 进行另一轮,因为它在 2 之前。

因此,在考虑每个数字时,我们只需要关心在顺序中排在它前面的数字的位置。在考虑2时,我们看1的位置? 1 是在 2 之前还是之后?它来了,我们不需要另一轮。但如果它来之前,我们将需要一个额外的回合。对于每个数字,我们会查看此条件并在必要时增加轮次计数。这样我们就可以在不模拟整个过程的情况下计算出总轮数。

#include <iostream>
#include <vector>

using namespace std;

int main(int argc,char const *argv[])
{
    int n;
    cin >> n;
    vector <int> v(n + 1),pos(n + 1);
    for(int i = 1; i <= n; ++i){
        cin >> v[i];
        pos[v[i]] = i;
    }
    int total_rounds = 1; // we'll always need at least one round because the input sequence will never be empty
    for(int i = 2; i <= n; ++i){
        if(pos[i] < pos[i - 1]) total_rounds++;
    }
    cout << total_rounds << '\n';
    return 0;
}

下次当您遇到此类问题时,请暂停一段时间,并尝试控制您在代码中模拟该过程的冲动。几乎可以肯定,会有一些巧妙的观察可以让您获得最佳解决方案。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其他元素将获得点击?
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。)
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbcDriver发生异常。为什么?
这是用Java进行XML解析的最佳库。
Java的PriorityQueue的内置迭代器不会以任何特定顺序遍历数据结构。为什么?
如何在Java中聆听按键时移动图像。
Java“Program to an interface”。这是什么意思?
Java在半透明框架/面板/组件上重新绘画。
Java“ Class.forName()”和“ Class.forName()。newInstance()”之间有什么区别?
在此环境中不提供编译器。也许是在JRE而不是JDK上运行?
Java用相同的方法在一个类中实现两个接口。哪种接口方法被覆盖?
Java 什么是Runtime.getRuntime()。totalMemory()和freeMemory()?
java.library.path中的java.lang.UnsatisfiedLinkError否*****。dll
JavaFX“位置是必需的。” 即使在同一包装中
Java 导入两个具有相同名称的类。怎么处理?
Java 是否应该在HttpServletResponse.getOutputStream()/。getWriter()上调用.close()?
Java RegEx元字符(。)和普通点?