著名的快速排序算法里有一个经典的划分过程:我们通常采用某种方法取一个元素作为主元,通过交换,把比主元小的元素放到它的左边,比主元大的元素放到它的右边。 给定划分后的 N 个互不相同的正整数的排列,请问有多少个元素可能是划分前选取的主元?
例如给定 , 排列是1、3、2、4、5。则:
- 1 的左边没有元素,右边的元素都比它大,所以它可能是主元;
- 尽管 3 的左边元素都比它小,但其右边的 2 比它小,所以它不能是主元;
- 尽管 2 的右边元素都比它大,但其左边的 3 比它大,所以它不能是主元;
- 类似原因,4 和 5 都可能是主元。
因此,有 3 个元素可能是主元。
输入格式:
输入在第 1 行中给出一个正整数 N(≤10^5); 第 2 行是空格分隔的 N 个不同的正整数,每个数不超过 10^9。
输出格式:
在第 1 行中输出有可能是主元的元素个数;在第 2 行中按递增顺序输出这些元素,其间以 1 个空格分隔,行首尾不得有多余空格。
输入样例:
5
1 3 2 4 5
输出样例:
3
1 4 5
思路:
本题难度稍大,一开始使用暴力循环方法,果然只能通过三个测试用例。
后来需要观察主元的特性:
如果一个元素是主元,首先必须满足:
(1)该元素的位置是正常排序的位置
(2)该元素前的最大元素必须比该元素小。
例如数列:1 3 2 4 5
主元1 4 5的位置与正常排序时1 2 3 4 5的位置是相同的,其次,每一个主元的前面都没有比他大的元素
例如数列: 5 4 3 1 2
数字3虽然与正常排序的位置相同,但是其前面有比他大的元素,因此3不是主元
知道这个规律以后就好处理了:
关键的判断循环如下:
for (int i = 0; i < N; i++)
//要满足为主元,首先需要该元素的位置为排序后的位置
//其次,该元素前的最大元素必须比这个元素小
{
max = max > store[i] ? max : store[i];//随时存储最大元素
if (store[i] != tep[i])tep[i] = 0;//如果位置不对,将该元素设为0
if (max > store[i])tep[i] = 0;//如果前面最大元素比该元素大,将该元素设置为0
if (tep[i] != 0)result.push_back(tep[i]);//如果该元素没有设为0,证明其是主元,存在result中
}
//其中tep数组是排序后的数组,store是排序前的数组
注意本题还有一个测试点,是如果没有主元需要先输出0,然后输出一个空行。
代码:
//1045 快速排序
#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
int main()
{
int N;
cin >> N;//输入元素个数
int temp, max = 0;//temp用于临时存储数据,max用于存放前面为止的最大数
vector<int> store, tep, result;
for (int i = 0; i < N; i++)//将所有元素存在store中
{
cin >> temp;
store.push_back(temp);
}
tep = store;
sort(tep.begin(), tep.end());//对原数组进行排序
for (int i = 0; i < N; i++)
//要满足为主元,首先需要该元素的位置为排序后的位置
//其次,该元素前的最大元素必须比这个元素小
{
max = max > store[i] ? max : store[i];//随时存储最大元素
if (store[i] != tep[i])tep[i] = 0;//如果位置不对,将该元素设为0
if (max > store[i])tep[i] = 0;//如果前面最大元素比该元素大,将该元素设置为0
if (tep[i] != 0)result.push_back(tep[i]);//如果该元素没有设为0,证明其是主元,存在result中
}
if (result.size() == 0)//如果没有主元,输出0,然后在输出一个空行,这是第三个测试点
{
cout << 0 << endl;
cout << endl;
return 0;
}
else
{
cout << result.size() << endl;
for (unsigned int i = 0; i < result.size() - 1; i++)
{
cout << result[i] << ' ';
}
cout << result[result.size() - 1] << endl;
}
return 0;
}
网友评论