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

C++ 从左到右遍历数组,收集尽可能多的数字,c++,algorithm,sorting,sequence,C++,Algorithm,Sorting,Sequence,CSES问题() 您将获得一个数组,该数组包含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>&

CSES问题()

您将获得一个数组,该数组包含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;
int n,res=0;
cin>>n;
int-arr[n];
拉斯泰尔;
对于(int i=0;i>arr[i];
auto it=lastEl.下限(arr[i]);
如果(it==lastEl.end())res++;
else lastEl.擦除(*它);
最后插入(arr[i]);
}

让我详细地解释一下我的思考过程,这样下次当你面对同样的问题时,你会更容易

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

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

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

#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;
}
请注意,数字的位置在这里至关重要。为什么我们需要对
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;
}
#包括
#包括
使用名称空间std;
int main(int argc,char const*argv[]
{
int n;
cin>>n;
向量v(n+1),pos(n+1);
对于(inti=1;i>v[i];
pos[v[i]]=i;
}
int total_rounds=1;//我们总是需要至少一轮,因为输入序列永远不会为空

对于(int i=2;i)为什么代码中有一个
set
?你能用简单的英语解释一下你的代码试图做什么?或者,它应该如何工作?而且,链接的问题只包含一个例子,所以你关于输出的陈述没有意义。我遍历了一次数组。如果元素arr[i]小于之前的所有元素,则我“打开”一个新序列,并将该元素保存为该序列中的最后一个元素。我将已打开序列的最后一个元素存储在集合中。如果元素arr[I]小于之前的一些元素,则我将使用其中最大的元素(但小于arr[I])获取已存在的序列,并用arr[i]替换此序列的最后一个元素。我指的是对下载的解决方案执行的三个测试。感谢您的反馈。噢,非常感谢!实际上,我误解了任务。我没有意识到每个子序列都必须由相邻的数字组成。