题目
思路
快速排序的应用,不需要写一遍快排的代码。
坑点是测试点2,行末需要在输出一个换行。
两种思路:
- 参考柳神的,给出划分后的数列,由快排主元的定义,比前面的数都大,比后面的数都小,则相当于主元本身已经排好序了,那么利用快排将原数组排好序,对应位置相同的有可能是主元。再进行一次最大值的验证,当其左侧的数均小于它时,可以确定为主元。
AC代码:
#include<bits/stdc++.h>
using namespace std;
int main(){
int n; cin>>n;
int a[n],b[n];
for(int i=0;i<n;i++){
cin>>a[i];
b[i]=a[i];
}
sort(a,a+n);
int max=0,step=0;
int c[100000];
for(int i=0;i<n;i++){
if(a[i]==b[i] && b[i]>max){
c[step++]=b[i];
}
if(b[i]>max) max=b[i];
}
cout<<step<<endl;
for(int i=0;i<step;i++){
cout<<c[i];
if(i!=step-1) cout<<' ';
}
cout<<endl;
}
- 第二张思路类似于B1040(算是另一类25分题喜欢的考法?),正向遍历数组,统计每一位左侧的最大值;反向遍历数组,统计每一位右侧的最小值,并记录在数组中。
两次遍历后,对每个a[i],都有对应leftMax[i]记录其左侧最大值,rightMin[i]记录其右侧最小值 。
再建立新数组储存主元,排序后输出。
AC代码:
#include<bits/stdc++.h>
using namespace std;
int main(){
int n; cin>>n;
int a[100001],lmax[100001],rmin[100001];
for(int i=0;i<n;i++){
cin>>a[i];
}
lmax[0] = 0; //从a[0]开始判断,此时a[0]左侧最大值为0
for(int i = 1; i < n; i++){ // 开始向右侧遍历
if(a[i-1] > lmax[i-1]){ //若左侧值a[i-1]大于左侧最大值,则对该a[i],其对应的左侧最大值为a[i-1]
lmax[i] = a[i-1];
}else{
lmax[i] = lmax[i-1]; //反之则仍为前一位的左侧最大值
}
}
rmin[n-1] = 1000000000; //从末地址开始找右侧最小值,对末位,无右侧最小值,故定义一个极大值作为其右侧最小值
for(int i = n-2; i >= 0; i--){ //从倒数第二位向左侧遍历,
if(a[i+1] < rmin[i+1]){ //若前一位的值比其右侧最小值小 ,则更新其右侧最小值
rmin[i] = a[i+1];
}else{
rmin[i] = rmin[i+1]; //反之,其右侧最小值仍为后一位的右侧最小值
}
}
int ans[100001];
int num=0;
//两次遍历后,对每个a[i],都有对应leftMax[i]记录其左侧最大值,rightMin[i]记录其右侧最小值
//找可能是主元的数
for(int i = 0; i < n; i++){
if(a[i] > lmax[i] && a[i] < rmin[i]){ //如果a[i]比它左边最大的数都大,比它右边最小的数都小
ans[num++] = a[i]; //则a[i]可能是主元,放入ans数组
}
}
cout<<num<<endl;
sort(ans,ans+num);
for(int i=0;i<num;i++){
cout<<ans[i];
if(i!=num-1) cout<<' ';
}
cout<<endl;
}