O(n) 时间的算法进行分数排名

来源:互联网 发布:阿里云域名无需备案 编辑:程序博客网 时间:2024/06/05 03:54

一 问题描述

遇到一个常见的分数排名问题,原题的要求是:

已知一个分数数组,数组里面是取值在0-100之间的分数,记为scoreArray。要求输出对应的排名数组scoreRankArray。
比如:scoreArray为[96,95,92,91,97,100,90,88,89,96];
对应应该输出positionArray为:[3,5,6,7,2,1,8,10,9,3]
同样分数的排名相同,但是后续的分数排名将累加。

二 解决方案

解决方案1:
使用比较法,判断数组中比自己分数大的分数的个数,若没有比自己高的分数,排名即为1。所以初始化个数为1。
算法时间复杂度: O(n^2)
算法空间复杂度:O(1)
对应下述的函数:
void getScoreRank(int *scoreArray,int len)

解决方案2:
1. 首先得到每个分数的人数,因为分数在0-100之间, 因此可以声明一个长度为101的数组scoreLibraryArray,数组每个元素的值表示对应下标的分数的个数。比如scoreLibraryArray[90]表示分数为90的人数。
2. 得到每个分数所在的排名,放在数组scoreFullArray中,scoreFullArray[90]表示表示分数为90的排名
3.遍历分数数组scoreArray,根据分数值和scoreFullArray数组中对应分数的排名,得到对应排名数组相应位的排名值。
算法时间复杂度:O(n)
算法空间复杂度:O(1)
对应下述的函数:
void getScoreRank_better(int *scoreArray,int len);

三 代码实现

使用C语言实现并测试一个数组的排名情况:

#include <stdio.h>#include <stdlib.h>void getScoreRank(int *scoreArray,int len);void getScoreRank_better(int *scoreArray,int len);int main () {    int scores[10] = {96,95,92,91,97,100,90,88,89,96};    int *scoreArray = scores;    static int arraySize = 10;    getScoreRank(scoreArray,arraySize);    getScoreRank_better(scoreArray,arraySize);    return 0;}void getScoreRank(int *scoreArray,int len) {    int arraySize = len;    int *scoreRankArray = (int *)malloc(sizeof(int)*arraySize);    for (int i = 0;i < arraySize;i++) {        int scoreRank = 1;        for (int j = 0;j < arraySize;j++) {            if (*(scoreArray+j) > *(scoreArray+i)) {                scoreRank++;            }        }        *(scoreRankArray+i) = scoreRank;    }    printf("score rank array is:\n[");    for (int i = 0;i < arraySize - 1;i++) {        printf("%d,",*(scoreRankArray+i));    }    printf("%d]\n",*(scoreRankArray + arraySize - 1));    free(scoreRankArray);    scoreRankArray = NULL;}void getScoreRank_better(int *scoreArray,int len) {     int arraySize = len;    int *scoreRankArray = (int *)malloc(sizeof(int)*arraySize);    static int scoreRange = 100;    int *scoreLibraryArray = (int *)malloc(sizeof(int) * (scoreRange + 1));    for (int i = 0;i < arraySize;i++) {        *(scoreRankArray + i) = 0;    }    for (int i = 0;i <= scoreRange;i++) {        *(scoreLibraryArray + i) = 0;    }    for (int i = 0;i < arraySize;i++) {        int scoreI = *(scoreArray + i);        *(scoreLibraryArray + scoreI) = *(scoreLibraryArray + scoreI) + 1;    }    int *scoreFullArray = (int *)malloc(sizeof(int) * (scoreRange+1));    for (int i = 0;i <= scoreRange;i++) {        *(scoreFullArray + i) = 0;    }    int rank = 1;    for (int i = 99;i >= 0;i--) {        rank += *(scoreLibraryArray + i + 1);        *(scoreFullArray + i) = rank;    }    *(scoreFullArray + scoreRange) = 1;    for (int j = 0;j < arraySize;j++) {        int score = *(scoreArray + j);        int scoreRank = *(scoreFullArray + score);        *(scoreRankArray + j) = scoreRank;    }    printf("better solution: score rank array is:\n[");    for (int i = 0;i < arraySize - 1;i++) {        printf("%d,",*(scoreRankArray + i));    }    printf("%d]\n",*(scoreRankArray + arraySize - 1));      free(scoreRankArray);    scoreRankArray = NULL;}       

四 运行结果

gcc编译后输出结果如下图:
run result

五 总结

针对大量的数据排名,比如高考分数省级排名(百万级别数据),使用优化后的算法的时间效率提升明显。所以针对分数数据的排名,结合分数是有一定取值范围,无须排序即可完成。与O(n) 时间的算法进行员工年龄排序有异曲同工之妙。该题描述和分析如下:

> 题目:某公司有几万名员工,请完成一个时间复杂度为O(n)的算法对该公司员工的年龄作排序,可使用O(1)的辅助空间。> > 分析:排序是面试时经常被提及的一类题目,我们也熟悉其中很多种算法,诸如插入排序、归并排序、冒泡排序,快速排序等等。这些排序的算法,要么是O(n2)的,要么是O(nlogn)的。可是这道题竟然要求是O(n)的,这里面到底有什么玄机呢?> 题目特别强调是对一个公司的员工的年龄作排序。员工的数目虽然有几万人,但这几万员工的年龄却只有几十种可能。上班早的人一般也要等到将近二十岁才上班,一般人再晚到了六七十岁也不得不退休。

六 注意事项

动态内存分配需要调用free()释放内存并重置为NULL,防止内存泄漏。

    free(scoreRankArray);    scoreRankArray = NULL;
0 0
原创粉丝点击