前K个高频单词-c++实现

692. 前K个高频单词 - 力扣(LeetCode)

给定一个单词列表 words 和一个整数 k ,返回前 k 个出现次数最多的单词。

返回的答案应该按单词出现频率由高到低排序。如果不同的单词有相同出现频率, 按字典顺序 排序。

示例 1:

输入: words = ["i", "love", "leetcode", "i", "love", "coding"], k = 2
输出: ["i", "love"]
解析: "i" 和 "love" 为出现次数最多的两个单词,均为2次。
    注意,按字母顺序 "i" 在 "love" 之前。

 我们可以先把 words 当中的单词按照 pair<string,int>的方式放到 一个 map 当中去,然后使用 sort()函数对 map 当中的 int (词频)进行排序,再把 排好序的 string ,放到一个 string vector 当中返回。

但是 sort()函数支持的是 随机迭代器,而 map 是双向迭代器,所以 map 不能直接用于 sort()函数,所以,我们想到把 map 当中的数据(key-value)放到一个 vector<pair<string,int>>当中去,因为 vector 的迭代器是随机迭代器,所以能使用 sort()函数。

但是,如果我们想要 使用 pair对象当中的 int (词频)来排序的话,在 sort()当中是支持仿函数的设定的,在 sort()的第三个参数,就是仿函数,所以,我们需要自己实现一个 int 比较的仿函数:
 

    class Greater
    {
        bool operator()(const int& x, const int& y)
        {
            return x > y;
        }
    };

然后在调用 sort()函数的时候调用这个 Greater的匿名对象就行了:

// 因为map 的迭代器是双向迭代器,不能用sort(),sort()需要随机迭代器
        vector<pair<string, int>> sortv(StringMap.begin(), StringMap.end());
        sort(sortv.begin(), sortv.end(), greater());

注意,这里给仿函数的形式是给 greater(),匿名对象的形式,因为 sort()函数是以参数列表的形式接收 这个 仿函数(其实就是一个类),所以要接受一个对象。

而在模版参数当中接收的仿函数,接收的是类型,所以是以 greater<T> 这样的形式给的,如下所示:
 

 当上述工作都完成之后,我们发现,我们输出的结果有误:
 

 由上述结果可知,并不是完全无序的,而是 一组一组 的无序。通过观察发现,是sort()函数的问题,sort()函数的底层是使用快排来实现的,快排是不稳定的排序,所谓不稳定就是,同一个值,应该按照原本在数组当中存储的顺序来进行排序。这才是稳定的,但是 快排是不稳定的。

所以才出现了上述的输出错误。

其实在库当中,sort()函数有一个 优化函数 :stable_sort(),这个就是 稳定的 快排。

 完整代码:

class Solution {
public:
    // 用于比较 int(词频)的仿函数
    // 可以使用 class,但是 class 当中成员不加 权限修饰符默认是 private
    // struct 默认是 public 的
    struct Greater
    {
        bool operator()(const pair<string, int>& x, const pair<string, int>& y)
        {
            return x.second > y.second;
        }
    };

    // 主函数
    vector<string> topKFrequent(vector<string>& words, int k) {
        map<string, int> StringMap;
        for(auto e : words)
        {
            StringMap[e]++;
        }

        // 因为map 的迭代器是双向迭代器,不能用sort(),sort()需要随机迭代器
        vector<pair<string, int>> sortv(StringMap.begin(), StringMap.end());
        stable_sort(sortv.begin(), sortv.end(), Greater());

        vector<string> retvector;
        for(int i = 0;i < k;i++)
        {
            retvector.push_back(sortv[i].first);
        }

        return retvector;
    }
};

当然,使用 sort()函数也可以解决,sort()函数不稳定,我们在 仿函数比较规则当中控制就可以了(控制,当词频相同时候,string排序当中小的在前):

class Solution {
public:
    // 用于比较 int(词频)的仿函数
    // 可以使用 class,但是 class 当中成员不加 权限修饰符默认是 private
    // struct 默认是 public 的
    struct Greater
    {
        bool operator()(const pair<string, int>& x, const pair<string, int>& y)
        {
            // 控制,当词频相同时候,string排序当中小的在前
            return x.second > y.second || (x.second == y.second && x.first < y.first);
        }
    };

    // 主函数
    vector<string> topKFrequent(vector<string>& words, int k) {
        map<string, int> StringMap;
        for(auto e : words)
        {
            StringMap[e]++;
        }

        // 因为map 的迭代器是双向迭代器,不能用sort(),sort()需要随机迭代器
        vector<pair<string, int>> sortv(StringMap.begin(), StringMap.end());
        sort(sortv.begin(), sortv.end(), Greater());

        vector<string> retvector;
        for(int i = 0;i < k;i++)
        {
            retvector.push_back(sortv[i].first);
        }

        return retvector;
    }
};

其实不使用 sort()之类的排序函数也是可以实现的,map 本身在输出的时候就有排序的效果,我们可以先用map 按string 来排序(string作为key),再用 int(词频)来排序就可以实现了(int 作为 key)。

但是注意,我们要的结果是降序的前 k 个,但是 map 默认是 升序的,如果 默认升序的后 k 个话,string 排序是反的。

其实,map 还有一个模版参数,可以控制升序和降序:

 他默认是 less()仿函数,我们传入一个库当中的 greater()仿函数就可以了:
完整代码实现:
 

class Solution {
public:
    // 主函数
    vector<string> topKFrequent(vector<string>& words, int k) {
        // 排序string
        map<string, int> StringMap;
        for(auto e : words)
        {
            StringMap[e]++;
        }

        // 排序 int(词频)
        multimap<int, string , greater<int>> intMap;
        for(auto& e : StringMap)
        {
            intMap.insert(make_pair(e.second, e.first));
        }

        vector<string> retvector;
        auto it = intMap.begin();
        while(k--)
        {
            retvector.push_back(it->second);
            it++;
        }

        return retvector;
    }
};

 还可以使用 set 来实现,也是写仿函数按照 出现 频率去比,当出现频率相同,手动判断,然后进行处理(再去按照字典排)。

代码实现:
 

class Solution {
public:
	class Compare
	{
	public:
		// 在set中进行排序时的比较规则
		bool operator()(const pair<string, int>& left, const
			pair<string, int>& right)
		{
			return left.second > right.second;
		}
	};
	vector<string> topKFrequent(vector<string>& words, int k)
	{
		// 用<单词,单词出现次数>构建键值对,然后将vector中的单词放进去,统计每
		//个单词出现的次数
		map<string, int> m;
		for (size_t i = 0; i < words.size(); ++i)
			++(m[words[i]]);
		// 将单词按照其出现次数进行排序,出现相同次数的单词集中在一块
		multiset<pair<string, int>, Compare> ms(m.begin(), m.end());
		// 将相同次数的单词放在set中,然后再放到vector中
		set<string> s;
		size_t count = 0; // 统计相同次数单词的个数
		size_t leftCount = k;
		vector<string> ret;
		for (auto& e : ms)
		{
			if (!s.empty())
			{
				// 相同次数的单词已经全部放到set中
				if (count != e.second)
				{
					if (s.size() < leftCount)
					{
						ret.insert(ret.end(), s.begin(), s.end());
						leftCount -= s.size();
						s.clear();
					}
					else
					{
						break;
					}
				}
			}
			count = e.second;
			s.insert(e.first);
		}
	}
}

  • 3
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

chihiro1122

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值