C ++设计:给出一个学生分数列表,按顺序获得分数的频率

时间:2011-10-14 21:03:56

标签: c++ algorithm data-structures stl map

我有一个C ++面试问题:

根据学生分数列表,按顺序获得分数的频率。 [使用c ++容器图]

我的想法:将得分列表放入地图中,其中得分为关键,频率为值。在添加密钥之前,请进行搜索。如果某个键是新的,请添加它并将其freq设置为1.如果不是,请按++ 1更新其频率。 O(nlgn)

然后,在新地图中反转键和值,其中将freq设置为键,将其得分设置为值。 O(nlgn)因为地图会自行排序。

记忆:O(n)

效率不高,因为我必须使用2张地图并进行2次排序。

欢迎提出任何意见或建议。

由于


  My code


    #include <iostream>
    #include <map>
    #include <algorithm>

    #include <time.h>

  using namespace std;
  const int M =10;
  int A[M] ;
  bool myFunc(pair<int, int> p1 , pair<double, int> p2)
  {
    //return p1.second > p2.second;
  }

   int scoreMap(int *A, const int& N)
   {
    if (A == NULL)
            return 1;
    map<int, int> map1;
    map<int, int>::iterator itr;
    int j = 0 ;
    while(j < N)
    {
            int myKey = (A[j]) ;
            itr = map1.find(myKey);
            if (itr == map1.end())
            {
                    map1.insert(pair<int, int>(myKey, 1));
            }
            else
            {
                    ++(itr->second);
            }
            ++j;
    }
    // print map1
    cout << "socre \t freq " << endl;
    for(itr = map1.begin(); itr != map1.end(); ++itr )
    {
            cout << itr->first << "\t" << itr->second << endl;
    }
    // use multimap
    multimap<int, int> map2;
    multimap<int, int>::iterator itr2;
    for (itr = map1.begin() ; itr != map1.end() ; ++itr )
    {
            map2.insert(pair<int, int>((*itr).second, (*itr).first)) ;
    }

    // print map2
    cout << "after sort " << endl;
    cout << "freq \t socre " << endl;
    for(itr2 = map2.begin(); itr2 != map2.end(); ++itr2 )
    {
            cout << (double)(itr2->first)/N << "\t" << itr2->second << endl;
    }
    return 0;
   }

   int main()
   {
    int N = 10;  int range=10;
    for (int i = 0 ; i < M ; ++i)
    {
            srand(time(NULL)+rand());
            //A[i] = rand()%range + (double)rand()/INT_MAX;
            A[i] = rand()%range ; // + (double)rand()/INT_MAX;
    //      sleep(1);
    }
    scoreMap(A, M);
    return 0;
   }

// EOF

时间O(nlgn),空间O(n),是否有更有效的解决方案? 感谢

3 个答案:

答案 0 :(得分:3)

假设得分是一个窄整数范围(1-100)

分数累积存储在成对的数组[得分范围]中,具有您的++ [得分]想法。

通过以迭代方式向下移动得分列表来进行频率的提取。 O(N + M)N得分范围+ M个结果/得分数。对结果进行排序。

Sample pseudo:

const size_t MAX_SCORE = 100; //  Min is assumed 0.
void scoreFrequencies(int [] scores, size_t N){
    pair<int,int> score_counts[MAX_SCORES];
    for(size_t i = 0; i < N; i++){
        score_counts[i].first++;
        score_counts[i].second = i;
    }
    sort( score_counts, score_counts+MAX_SCORES );
    for(size_t score_decreasing = MAX_SCORES-1; 
             score_counts[score_decreasing].first!=0 && score_decreasing >=0; 
             score_decreasing--)
         cout<< (score_counts.second) <<": " << 
                 ( score_counts.first*1.0/N ) << endl;
}

可以看出,通过这种方法,sort(...)之前的score_counts顺序是不必要的,因此map无济于事。

答案 1 :(得分:2)

不使用地图,只需使用数组类型std::pair<int, int>定义所有分数的直方图。一个成员将是分数,另一个成员是频率。最初得分与它们所在的数组索引的值相同,但是当您尝试访问每个特定的得分索引时,您应该只进行初始化,否则您将最终初始化一堆不存在的得分。然后在填写分数的直方图后,根据分数的频率对数组进行排序。由于直方图中的分数基本上就像非常简单的散列查找,因此总体时间应该非常快(每个分数查找和相关频率增量为... O(1),并且排序为O(n log n))

这里有一些代码可以帮助解释:

std::pair<int, int> scores[SCORE_RANGE] = {0}; //zero-out the entire array

//...iterate through your score data
for (int i=0; i < SCORE_DATA_SIZE; i++)
{
    int score_val = raw_score_data[i];

    if (scores[score_val].first == 0)
    {
        scores[score_val].first = score_val;
    }

    scores[score_val].second++;
}

//now sort your scores array based on the frequency which is stored in the second
//member of the std::pair structure

答案 2 :(得分:0)

  

我的想法:将得分列表放入地图中,其中得分为关键,频率为值。

到目前为止,很好,

  

在添加密钥之前,请进行搜索。如果某个键是新的,请添加它并将其freq设置为1.如果不是,请按++ 1更新其频率。 O(nlgn)

检查现有的地图条目是不必要的,也是浪费的。该条目将在第一次引用时弹出(具有默认值)。就这样做:

++scoreMap[score];

这不会改变你的大O,但确实会让它变得更快。

  

然后,在新地图中反转键和值,其中将freq设置为键,将其得分设置为值。 O(nlgn)因为地图会自行排序。

您无法使用新地图,因为分数不一定是唯一的。但您可以使用set<pair>

为了纪念Ubuntu 11.10(和g ++ 4.6!)在我的电脑上正确安装,以下是如何使用lambdas来解决这个问题:

  map<int, int> scoreMap;
  for_each(istream_iterator<int>(cin), istream_iterator<int>(),
    [&scoreMap] (int i) { ++scoreMap[i]; } );
  set<pair<int,int>> freqMap;
  for_each(scoreMap.begin(), scoreMap.end(),
    [&freqMap] (const pair<int,int>& p) {
      freqMap.insert(make_pair(p.second, p.first));
    } );
  for_each(freqMap.rbegin(), freqMap.rend(),
    [] (const pair<int,int>& p) {
      cout << p.second << "/" << p.first << "\n";
    } );