版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
题目链接:点击查看
题目大意:根据快速排序的定义,找出主元,主元就是在未排序之前,当前位置之前的数都比其自身小,当前位置之后的数都比其自身大
题目分析:这个题可以暴力混分。。但没必要,n*n的时间复杂度就已经1e10了,肯定不是最优解,因为涉及到了最大值和最小值,我们可以用线性dp求一下截止到每个位置的最大值和最小值,正这跑一遍最大值,倒着跑一遍最小值,最后再正这跑一遍就出答案了,正这跑的时候只要满足条件的数,就可以记录下来了,条件就是当前的数小于等于记录的最小值,大于等于记录的最大值即可
网上说还有一种做法,我有考虑到,但没考虑的那么全面就没敢尝试,而且时间复杂度比这个要大,这个的时间复杂度是3*n,而那个的做法是说,主元都是在当前序列排序后位置不变的元素,所以我们可以开个辅助数组排个序,并且可以正这跑一遍最大值,边跑边判断就能出答案了,即当前的值比之前的最大值都要大,并且当前的值在排序后位置不变,不过这样一来有了排序,时间复杂度就到了nlogn了,而且这个原理不明。。有点玄学,还是正反跑一遍线性dp比较好理解
注意最后需要特别判断一下主元数为0的情况
代码:
#include<iostream>
#include<cstdlib>
#include<string>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<climits>
#include<cmath>
#include<cctype>
#include<stack>
#include<queue>
#include<list>
#include<vector>
#include<set>
#include<map>
#include<sstream>
#include<unordered_map>
using namespace std;
typedef long long LL;
const int inf=0x3f3f3f3f;
const int N=1e5+100;
struct Node
{
int mmax,mmin;
}dp[N];
int a[N];
int main()
{
// freopen("input.txt","r",stdin);
int n;
scanf("%d",&n);
for(int i=1;i<=n;i++)
scanf("%d",a+i);
dp[0].mmax=-inf;
dp[n+1].mmin=inf;
for(int i=1;i<=n;i++)
dp[i].mmax=max(a[i],dp[i-1].mmax);
for(int i=n;i>=1;i--)
dp[i].mmin=min(a[i],dp[i+1].mmin);
vector<int>ans;
for(int i=1;i<=n;i++)
if(dp[i].mmax<=a[i]&&dp[i].mmin>=a[i])
ans.push_back(a[i]);
cout<<ans.size()<<endl;
if(ans.size())
{
cout<<ans[0];
for(int i=1;i<ans.size();i++)
cout<<' '<<ans[i];
}
cout<<endl;
return 0;
}