1. 程式人生 > >PAT B1045 快速排序 (25 分)

PAT B1045 快速排序 (25 分)

pre ase hit pause div 數組 格式 lan code

著名的快速排序算法裏有一個經典的劃分過程:我們通常采用某種方法取一個元素作為主元,通過交換,把比主元小的元素放到它的左邊,比主元大的元素放到它的右邊。 給定劃分後的 N 個互不相同的正整數的排列,請問有多少個元素可能是劃分前選取的主元?

例如給定 $N = 5$, 排列是1、3、2、4、5。則:

  • 1 的左邊沒有元素,右邊的元素都比它大,所以它可能是主元;
  • 盡管 3 的左邊元素都比它小,但其右邊的 2 比它小,所以它不能是主元;
  • 盡管 2 的右邊元素都比它大,但其左邊的 3 比它大,所以它不能是主元;
  • 類似原因,4 和 5 都可能是主元。

因此,有 3 個元素可能是主元。

輸入格式:

輸入在第 1 行中給出一個正整數 N(≤); 第 2 行是空格分隔的 N 個不同的正整數,每個數不超過 1。

輸出格式:

在第 1 行中輸出有可能是主元的元素個數;在第 2 行中按遞增順序輸出這些元素,其間以 1 個空格分隔,行首尾不得有多余空格。

輸入樣例:

5
1 3 2 4 5

輸出樣例:

3
1 4 5
#include <stdio.h>
#include <algorithm>
#include <cstring>
using namespace std;
const int maxn = 100010, mod = 1000000007;
int s[maxn];
int p[maxn] = { 0 };
int ind[maxn] = { 0 };
int main() {
    
    
int N = 0; int count = 0; scanf("%d", &N); for (int i = 0; i < N; i++) { scanf("%d", &s[i]); } int left = s[0], right = s[N - 1]; for (int i = 0; i < N; i++) { if (s[i] > left) { left = s[i]; } p[i] = left; }
for (int i = N - 1; i >= 0; i--) { if (s[i] <= right && s[i] == p[i]) { count++; ind[i] = 1; } if (s[i] <= right) right = s[i]; } if(count)printf("%d\n", count); else printf("%d\n\n",count); for (int i = 0; i < N; i++) { if (ind[i] == 1) { count--; if (count)printf("%d ", s[i]); else { printf("%d", s[i]); break; } } } system("pause"); return 0; }

註意點:用最笨的辦法一個個元素遍歷他之前和之後的時間復雜度O(n2)太高。這裏用的技巧是先把每個元素左邊(包括自己)的最大值放在一個數組中保存起來,再從後往前遍歷,獲得元素右邊的最小值,來判斷。由於得到的滿足條件的值肯定是根據索引從小到大排列的,所以直接遍歷輸出即可。

PAT B1045 快速排序 (25 分)