【问题标题】:Find the most frequent word over the latest K words找出最近 K 个词中出现频率最高的词
【发布时间】:2014-09-24 07:11:05
【问题描述】:

我试图解决这个问题:

这个想法很简单,你的程序会不断地从流中读取新单词,但由于存储空间有限,你的程序只能记住最近的 K 个单词。因此,当第 (K+1) 个单词到达时,您的程序会忘记第 1 个单词,当第 (k+2) 个单词到达时,您的程序会忘记第 2 个单词,依此类推。

我们希望您在每次出现新词时,在最新的K 词中找到最常用的词。我尝试使用映射(作为哈希表)双端队列(以维护输入流)来解决问题。下面是我尝试过的代码,但在某些情况下它没有给出预期的结果。

#include <bits/stdc++.h>
#include <string>
using namespace std;
#define ps pair<string,int>
map<string,int>dir;
int lookup( string name)
{

    map<string,int>::iterator it;
    dir[name]+=1;
    it=dir.find(name);
    return it->second;
}
void update(string name)
{
    map<string,int>::iterator it;
    it=dir.find(name);
    if(it!=dir.end()&& it->second>=1)
    dir[name]-=1;
    else dir[name]=0;
}
string small(string s1,string s2)
{
    int l=min(s1.size(),s2.size());
    if(s1==s2)return s1;
    else
    {
        for(int i=0;i<l;i++)if(s1[i]>s2[i])return s2;
        return s1;
    }
}
int main() 
{
    ios_base::sync_with_stdio(false);
    int n,k;
    int tc,cs=0;
    cin >> tc;
    while(tc--){cout<<"Case "<<++cs<<":"<<endl;
    cin >> n >> k;
    string words;
    deque<ps>Q;
    deque<ps>::iterator it;
    Q.clear();
    dir.clear();
    int max =-1;
    string mf;
    while(n--)
    {
        cin>> words;
        if(Q.size()<k)
        {
            int c = lookup(words);
            Q.push_back(ps(words,c));
            it=Q.end()-1;
            if(it->second > max)
            {
                    max = it->second;
                    mf = it->first;
            }
            else if(max==it->second)
            {
                max = it->second;
                mf = small(mf,it->first);
            }
            cout <<mf<<" "<<max<<endl;
        }
        else
        {
            map<string,int>::iterator itm;
            if(Q.size() >= k)
            {
                it=Q.begin();
                update(it->first);
                itm=dir.find(it->first);
                if(itm->second>0)
                max-=1;
                Q.pop_front();
                int c = lookup(words);
                Q.push_back(ps(words,c));
                it=Q.end()-1;
                itm=dir.find(mf);
                if(it->second > itm->second)
                {
                    max = it->second;
                    mf = it->first;
                }
                else if(it->second == itm->second)
                {
                    max = it->second;
                    mf = small(itm->first,it->first);
                }
                cout <<mf<<" "<<max<<endl;
            }

        }
    }
    }
    return 0;
}

和测试用例:

Sample test cases:
  1
  8 3
  hello
  hi
  who
  hi
  hi
  hello
  who
  when

correct output 
Case 1:
  hello 1
  hello 1
  hello 1
  hi 2
  hi 2
  hi 2
  hello 1
  hello 1

Mine code output
Case 1:
  hello 1
  hello 1
  hello 1
  hi 2
  hi 2
  hi 2
  who 1
  when 1

【问题讨论】:

  • 基本思想:维护一个单词图来计数。还要维护一个 k 大小的单词数组。当输入一个新单词时,检查数组的大小。如果数组已满,则删除最旧的单词,将元素下移,添加新元素;减少地图中(现在已删除的)最旧单词的计数,增加地图中新单词的计数。打印地图中值最大的单词。继续
  • @inspectorG4dget 我尝试了同样的想法,我使用地图来存储单词及其频率,当新单词出现时。我正在使用 deque 来存储单词,当它达到限制 k 时,我将删除旧单词并通过降低它的频率再次维护地图。我正在做同样的事情,但得到错误的答案。这里是问题链接[link]spoj.com/problems/WORDCNT2
  • 您不需要双端队列 - 具有最大大小的队列就足够了。我无法提供实现细节,因为我没有 C++ 所需的专业知识
  • “它有时不符合我的要求”。 “当输入是 XYZ 时,输出是 ABC,而我期望 IJK”。哪种措辞可能会吸引更多答案?你决定。
  • #include &lt;bits/stdc++.h&gt; 不是标准的,可能会阻止使用其他实现的潜在贡献者。首选可移植代码。

标签: c++ data-structures stl


【解决方案1】:

以下可能会有所帮助:

class Counter
{
public:
    Counter(std::size_t size) : max_size(size) {}

    void AddWord(const std::string& word)
    {
        if (words.size() == max_size) {
            auto it = counts.find(words.front());
            --it->second;
            if (it->second == 0) {
                counts.erase(it);
            }
            words.pop();
        }
        words.push(word);
        ++counts[word];
    }

    const std::pair<const std::string, std::size_t>& getMax() const
    {
        return *std::max_element(counts.begin(), counts.end(),
        [](const std::pair<const std::string, std::size_t>& lhs, const std::pair<const std::string, std::size_t>& rhs)
        {
            return std::tie(lhs.second, rhs.first) < std::tie(rhs.second, lhs.first);
        });
    }

private:
    std::size_t max_size;
    std::queue<std::string> words;
    std::map<std::string, std::size_t> counts;
};

Live example

【讨论】:

    【解决方案2】:

    我已修改 Jarod42 的解决方案以与 g++4.3.2 一起使用,但该方法与 max_element 函数太慢了。需要更快的算法。

    #include <algorithm>
    #include <iostream>
    #include <string>
    #include <cstdio>
    #include <map>
    #include <queue>
    using namespace std;
    
    int max_size;
    string words[100000];
    map<string, size_t> counts;
    int ifrontword,ilastword;
    
    bool mycmp( pair<const string, size_t>& lhs,  pair<const string, size_t>& rhs){
      if (lhs.second==rhs.second) return rhs.first<lhs.first;
      else return lhs.second<rhs.second;
    }
    map<string, size_t>::iterator it;
    
    void AddWord(string& word){    
      if (ilastword-ifrontword == max_size) {
        counts[words[ifrontword]]--;
        if (counts[words[ifrontword]]==0)
          counts.erase(words[ifrontword]);
        ifrontword++;
      }
      words[ilastword++]=word;
      counts[word]++;
    }
    
    pair<const string, size_t>& getMax() {
      return *max_element(counts.begin(), counts.end(), mycmp);
    }
    
    int main(){
      ios_base::sync_with_stdio(false);
      int n,k;
      int tc,cs=0;
      string word;
      scanf("%d",&tc);
      while(tc--){
        cout<<"Case "<<++cs<<":"<<endl;
        scanf("%d%d",&n,&k);
        max_size=k;
        counts.clear();
        ilastword=ifrontword=0;
        while(n--){
          cin>> word;
          AddWord(word);
          pair<const string, size_t> &p = getMax();
          cout << p.first << " " << p.second << endl;
        }
      }
      return 0;
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-05-02
      • 2012-07-17
      • 2017-07-01
      • 2023-03-14
      • 1970-01-01
      • 1970-01-01
      • 2013-12-20
      • 1970-01-01
      相关资源
      最近更新 更多