There is a classical process named partition in the famous quick sort algorithm. In this process we typically choose one element as the pivot. Then the elements less than the pivot are moved to its left and those larger than the pivot to its right.
Given N distinct positive integers after a run of partition, could you tell how many elements could be the selected pivot for this partition?
For example, given N=5 and the numbers 1, 3, 2, 4, and 5. We have:
- 1 could be the pivot since there is no element to its left and all the elements to its right are larger than it;
- 3 must not be the pivot since although all the elements to its left are smaller, the number 2 to its right is less than it as well;
- 2 must not be the pivot since although all the elements to its right are larger, the number 3 to its left is larger than it as well;
- and for the similar reason, 4 and 5 could also be the pivot.
Hence in total there are 3 pivot candidates.
Input Specification:
Each input file contains one test case. For each case, the first line gives a positive integer N (≤105). Then the next line contains N distinct positive integers no larger than 109. The numbers in a line are separated by spaces.
Output Specification:
For each test case, output in the first line the number of pivot candidates. Then in the next line print these candidates in increasing order. There must be exactly 1 space between two adjacent numbers, and no extra space at the end of each line.
Sample Input:
5 1 3 2 4 5
Sample Output:
3 1 4 5
方法1:
最初我采用的是比较朴素的算法,对于每一个元素,分别判断他左边的元素是否全小于他,右边元素是否全部大于他,代码如下,O(n2)的复杂度,但是会导致超时:
注意测试点2,当 count == 0时,还要多输出一个空行。
#include<cstdio> const int MAXN = 100010; int number[MAXN], result[MAXN]; int main(){ int N,count = 0; scanf("%d", &N); for(int i = 0 ; i < N; i++){ scanf("%d", &number[i]); } for(int i = 0 ; i < N; i++){ int temp = number[i]; int flag = 1; if( i > 0 ){ for(int j = i ; j >= 0 ; j--){//首先判断左边的元素 if(number[j] > temp) { flag = 0; break; } } if(flag == 0) continue; else if(flag == 1){ for(int k = i ; k < N ; k++){//右边元素 if(number[k] < temp) { flag = 0; break; } } } } else if( i == 0){ for(int k = i ; k < N ; k++){//右边元素 if(number[k] < temp) { flag = 0; break; } } } if(flag){ result[count++] = temp; } } printf("%d\n", count); if(count == 0) printf("\n"); else{ for(int i = 0; i< count; i++){ if(i == count - 1){ printf("%d", result[i]); } else{ printf("%d ", result[i]); } } return 0; } }
方法2:
采用排序的方法,假如一个数是pivot的话,那么经过排序,他的位置是不会变的(因为左边的数全部小于他,右边的数全部大于他),但是要注意,还有别的情况可能导致位置不变,即两边大于他或小于他的数的数量是相等的(比如5 2 3 4 1,虽然3不是pivot但是排序后 1 2 3 4 5,3的位置不变,因为左边5>3 2<3,右边4>3 1<3,5和1交换位置,虽然格局大变,但是3并不能感觉到),因此要多加一个判断条件,left_max,在遍历的同时随时更新left_max,保证pivot > left_max即可。
时间复杂度为排序的复杂度O(nlogn)
#include<cstdio> #include<algorithm> using namespace std; const int MAXN = 100010; int number[MAXN], sort_number[MAXN], result[MAXN]; int main(){ int N,count = 0; scanf("%d", &N); for(int i = 0; i< N; i++){ scanf("%d", &number[i]); sort_number[i] = number[i]; } sort(sort_number, sort_number + N); int max = 0; for(int i = 0; i < N; i++){ if(sort_number[i] == number[i] && number[i] > max){ result[count++] = number[i]; } if(number[i] > max)//找到该元素左边的最大值 max = number[i]; } printf("%d\n", count); if(count == 0) printf("\n"); else{ for(int i = 0; i< count; i++){ if(i == count - 1){ printf("%d", result[i]); } else{ printf("%d ", result[i]); } } } return 0; }
方法3:
受方法2和课本《算法笔记》启发,可以开辟一个数组LeftMax[],从左到右遍历,记录该位置左边的最大值;然后从右到左遍历,记录右边的最小值,当满足 number[i]<=smallest(因为smallest的初值是number[N - 1]可能会有相等情况) && number[i] == LeftMax[i] (LeftMax为本身,说明该值为左边最大值)即为满足条件的值。
时间复杂度O(n)。
#include<cstdio> #include<algorithm> using namespace std; const int MAXN = 100010; int number[MAXN], result[MAXN]; int LeftMax[MAXN]; int main(){ int N,count = 0; scanf("%d", &N); for(int i = 0; i< N; i++){ scanf("%d", &number[i]); } LeftMax[0] = number[0]; for(int i = 0; i < N; i++){ if(i > 0) LeftMax[i] = LeftMax[i - 1]; if(number[i] > LeftMax[i]) LeftMax[i] = number[i]; } int smallest = number[N - 1]; for(int j = N - 1; j >= 0 ; j--){ if(number[j] <= smallest){ smallest = number[j]; if(number[j] == LeftMax[j]){ result[count++] = number[j]; } } } sort(result, result + count); printf("%d\n", count); if(count == 0) printf("\n"); else{ for(int i = 0; i< count; i++){ if(i == count - 1){ printf("%d", result[i]); } else{ printf("%d ", result[i]); } } } return 0; }