题目描述
快速排序中,每一次划分我们都会选定一个元素作为枢轴。划分结束之后枢轴左边的数值都比枢轴小,枢轴右边的数都比枢轴大。现在给定N(0<N<10^5)
个全都不相同的正整数,这些数小于10^9
。求:第一次划分中,枢轴元素的位置不会改变的情况有多少种。例如:
Sample Input:
5
1 3 2 4 5
Sample Output:
3
1 4 5
解题思路
假设我们现在要判断i
位置的元素是否符合要求,那么我们就需要判断区间[0,i-1]
的元素是否都小于arr[i]
,并且区间[i+1,N)
的元素都要大于arr[i]
。这等价于判断区间[0,i-1]
的最大值是否小于arr[i]
,区间[i+1,N)
的最小值是否大于arr[i]
。
根据上文的等价判定,我们首先正序遍历元素,标记符合区间[0,i-1]
的最大值小于arr[i]
的元素为true
。之后再逆序遍历元素,标记区间[i+1,N)
的最小值大于arr[i]
并且tag[i]==true
的元素为true
,不是的修改为false
。遍历的过程中还需要哦记录当前区间[0,i-1]
或[i+1,N)
内的最大值或最小值。
最后的输出,只要tag[i]==true
成立,该元素便符合要求。
实现代码
/*************************************************************************
* > File Name: pat1101.cpp
* > Author: ZQKC
* > Mail: 1979408672@qq.com
* > Created Time: Sun 31 Jan 2016 07:25:17 PM CST
************************************************************************/
#include <iostream>
#include <cstdio>
#include <cstring>
#define MAX_NUM 1000000001
#define MIN_NUM -1
bool tag[100005]; //标记数组
int arr[100005]; //
int main()
{
int N,sum;
while( ~scanf("%d",&N) )
{
memset(tag, 0x00, sizeof(tag));
for (int i=0; i<N; ++i)
{
scanf("%d",&arr[i]);
}
int max = MIN_NUM;
for (int i=0; i<N; ++i)
{
//i之前的最大值是否小于arr[i]
if ( arr[i] > max )
{
max = arr[i];
tag[i] = true;
}
}
int min = MAX_NUM;
sum = 0;
for (int i=N-1; i>=0; --i)
{
//i之后的最小数值是否小于arr[i]
if ( arr[i]<min && tag[i] )
{
min = arr[i];
++sum;
}
else if ( arr[i] < min )//记录[i,N)的最小值
{
min = arr[i];
tag[i] = false;
}
else
{
tag[i] = false;
}
}
printf("%d\n",sum);
for(int i=0; i<N; ++i)
{
if(tag[i])
{
printf("%d",arr[i]);
--sum;
if(sum)
printf(" ");
}
}
printf("\n");
}
return 0;
}