【分治】输出前k大的数
描述
给定一个数组,统计前k大的数并且把这k个数从大到小输出。
输入第一行包含一个整数n,表示数组的大小。n < 100000。
第二行包含n个整数,表示数组的元素,整数之间以一个空格分开。每个整数的绝对值不超过100000000。
第三行包含一个整数k。k < n。输出从大到小输出前k大的数,每个数一行。样例输入
10 4 5 6 9 8 7 1 2 3 0 5
样例输出
9 8 7 6 5
排序后再输出,复杂度 O(nlogn)
用分治处理: 复杂度 O(n+mlogm)
思路:把前m大的都弄到数组最右边,然后对这最右边m个元素排序,
再输出
关键 : 利用快排思想在O(n)时间内实现把前m大的都弄到数组最右边
1 #include<iostream> 2 using namespace std; 3 int n; 4 int a[100010]; 5 int k; 6 int partition(int s, int e) 7 { 8 int key = a[s]; 9 int i = s; 10 int j = e; 11 while (i < j) 12 { 13 while (a[j] >= key & i < j) 14 { 15 j--; 16 } 17 while (a[i] <= key & i < j) 18 { 19 i++; 20 } 21 swap(a[i], a[j]); 22 } 23 if (a[i] < key) 24 { 25 swap(a[s], a[i]); 26 } 27 else 28 swap(a[s], a[i - 1]); 29 return i; 30 } 31 void quickSort(int s,int e) 32 { 33 if (s < e) 34 { 35 int m = partition(s, e); 36 quickSort(s, m - 1); 37 quickSort(m+1, e); 38 } 39 } 40 void arrangeRight(int s,int e,int k) 41 { 42 if (e - s + 1 == k)//如果要找到大数个数就是数组长度,不进行操作,直接排序 43 { 44 return; 45 } 46 //找一个基准数,使比这个数大的都在右边,小的都在左边 47 int key = a[s]; 48 int i = s; 49 int j = e; 50 while (i < j) 51 { 52 while ((a[j] >= key) && (i < j)) 53 { 54 j--; 55 } 56 while ((a[i] <= key) &&( i < j)) 57 { 58 i++; 59 } 60 swap(a[i], a[j]); 61 } 62 if (a[i] < key) 63 { 64 swap(a[s], a[i]); 65 } 66 else 67 { 68 swap(a[s],a[i-1]); 69 } 70 int index = i;//最后基准数的位置 71 int len = e - index + 1; 72 if (len == k) 73 { 74 return; 75 } 76 else if (len > k)//找到的大数多余规定的,再往右缩小范围 77 { 78 arrangeRight(index+1,e,k); 79 } 80 else//找到的大数不够k个,往左扩大寻找范围,已找到len个,还差len-m个 81 { 82 arrangeRight(s,index-1,k-len); 83 } 84 } 85 int main() 86 { 87 cin >> n; 88 for (int i = 0; i < n; ++i) 89 { 90 cin >> a[i]; 91 } 92 cin >> k; 93 arrangeRight(0, n - 1,k); 94 quickSort(n-k,n-1); 95 for (int i = n-1; i >= n - k; --i) 96 { 97 cout << a[i] << endl; 98 } 99 system("pause"); 100 return 0; 101 }