1. 程式人生 > >1038. 統計同成績學生

1038. 統計同成績學生

本題要求讀入N名學生的成績,將獲得某一給定分數的學生人數輸出。

輸入格式:

輸入在第1行給出不超過105的正整數N,即學生總人數。隨後1行給出N名學生的百分制整數成績,中間以空格分隔。最後1行給出要查詢的分數個數K(不超過N的正整數),隨後是K個分數,中間以空格分隔。

輸出格式:

在一行中按查詢順序給出得分等於指定分數的學生人數,中間以空格分隔,但行末不得有多餘空格。

輸入樣例:
10
60 75 90 55 75 99 82 90 75 50
3 75 90 88
輸出樣例:
3 2 0

演算法:

  1. 演算法開始。
  2. 讀入N,N個成績,要查詢分數數量K,K個要查詢的成績。
  3. 用qsort對N個成績進行降序排序。
  4. 查詢第i個成績,如果i不小於K,則跳到第十六步。
  5. 如果begin大於等於end,則跳到第十五步。
  6. 如果begin上的成績大於要查詢的成績,end上的成績小於要查詢的成績,進行下一步,否則跳到第十一步。
  7. middle=(begin+end)/2。
  8. 如果middle上的成績大於要查詢的成績,則begin=middle-1,跳回第五步。
  9. 如果middle上的成績小於要查詢的成績,則end=middle+1,跳回第五步。
  10. 如果middle上的成績等於要查詢的成績,則middle一直加一,直到middle上的成績小於要查詢的成績或者middle等於N-1,將middle賦值給tmp。跳到第十三步。
  11. 如果begin上的成績等於要查詢的成績,則begin一直加一,直到begin上的成績小於要查詢的成績或者begin等於N-1,將begin賦值給tmp,跳到第十三步。
  12. 如果end上的成績等於要查詢的成績,則end一直加一,知道end上的成績小於要查詢的成績或者end等於N-1,將end賦值給tmp,跳到第十三步。
  13. 如果tmp上的成績小於要查詢的成績則tmp減一。
  14. 如果tmp上的成績不大於要查詢的成績而且tmp不小於零,count加一,tmp減一。
  15. i加一,回到第四步。
  16. 輸出每個要查詢成績的count。
  17. 演算法結束。
#include <stdio.h>
#include <stdlib.h>
int cmp(const void* v1, const void* v2);
int main(void) {
	int n, k, i, begin, end, middle, tmp, flag;
	int* grades;
	int* search;
	int* count;
	scanf_s("%d", &n);
	grades = (int*)calloc(n, sizeof(int));
	for (i = 0; i < n; i++) {
		scanf_s("%d", grades + i);
	}
	scanf_s("%d", &k);
	search = (int*)calloc(k, sizeof(int));
	count = (int*)calloc(k, sizeof(int));
	for (i = 0; i < k; i++) {
		scanf_s("%d", search + i);
	}
	qsort(grades, n, sizeof(int), cmp);
	for (i = 0; i < k; i++) {
		begin = 0;
		end = n - 1;
		flag = 0;
		do {
			if (grades[begin] == search[i]) {
				while ((grades[begin] == search[i])&&(begin < n)) {
					begin++;
				}
				tmp = begin;
				flag = 1;
				break;
			}
			else if (grades[end] == search[i]) {
				while ((grades[end] == search[i]) && (end < n)) {
					end++;
				}
				tmp = end;
				flag = 1;
				break;
			}
			middle = (begin + end) / 2;
			if (grades[middle] == search[i]) {
				while (grades[middle] == search[i] && middle < n) {
					middle++;
				}
				tmp = middle;
				flag = 1;
				break;
			}
			else if (grades[middle] > search[i]) {
				begin = middle + 1;
			}
			else if (grades[middle] < search[i]) {
				end = middle - 1;
			}
		} while (begin < end);
		if (flag) {
			if (grades[tmp] < search[i]) {
				tmp--;
			}
			while (grades[tmp] == search[i]) {
				tmp--;
				count[i]++;
			}
		}
	}
	for (i = 0; i < k; i++) {
		printf("%d", count[i]);
		if (i != k - 1) {
			putchar(' ');
		}
	}
	free(grades);
	free(count);
	free(search);
	return 0;
}
int cmp(const void* v1, const void* v2) {
	return *((int*)v2) - *((int*)v1);
}

但是這個演算法儘管運用了qsort和二分查詢法,但是時間複雜度達到了O(nlogn),最後個測試點執行超時了。 下面來個專門解決問題的演算法。
  1. 演算法開始。
  2. 讀入N。
  3. 每讀入一個成績i,就對grades[i]加一。
  4. 讀入K。
  5. 每讀入一個成績i,就輸出grades[i]。如果i不等於K-1,就輸出一個空格。
  6. 演算法結束。
是個方法時間複雜度只有O(n)。下列程式碼編寫於VS2015,若要在PAT上執行,修改sanf_s即可。
#include <stdio.h>
#include <stdlib.h>
int main(void) {
	int* grades;
	int n, k, i, tmp;
	scanf_s("%d", &n);
	grades = (int*)calloc(101, sizeof(int));
	for (i = 0; i < n; i++) {
		scanf_s("%d", &tmp);
		grades[tmp]++;
	}
	scanf_s("%d", &k);
	for (i = 0; i < k; i++) {
		scanf_s("%d", &tmp);
		printf("%d", grades[tmp]);
		i != k - 1 ? putchar(' '):putchar('\0');//i != k - 1 ? putchar(' '):putchar(NULL); 這樣也對。
	}
        free(grades);
	return 0;
}