LeetCode 451. Sort Characters By Frequency ***** map按值排序转vector,优先队列,频率当下标

一、题目

Given a string, sort it in decreasing order based on the frequency of characters.

Example 1:

Input:
"tree"

Output:
"eert"

Explanation:
'e' appears twice while 'r' and 't' both appear once.
So 'e' must appear before both 'r' and 't'. Therefore "eetr" is also a valid answer.

Example 2:

Input:
"cccaaa"

Output:
"cccaaa"

Explanation:
Both 'c' and 'a' appear three times, so "aaaccc" is also a valid answer.
Note that "cacaca" is incorrect, as the same characters must be together.

Example 3:

Input:
"Aabb"

Output:
"bbAa"

Explanation:
"bbaA" is also a valid answer, but "Aabb" is incorrect.
Note that 'A' and 'a' are treated as two different characters.
题意:题目很长题意很简单。给定一个字符串,按照字母出现的频率由大到小输出。

注意:后边的举例就是一直在强调的,字符串的题注意事项,字符集的范围,大小写,返回的顺序,空字符。

        该题范围就是大小写字母并且大小写有别,对于出现频率次数相同的串返回顺序任意。

思路:1.统计字符串中各个字母出现的频率存储在map中。

          2.对map按照频率由大到小排序,这里注意是map中按照值排序。

          第一反应是利用stl中提供的sort算法实现,这个想法是好的,不幸的是,sort算法有个限制,利用sort算法只能对序列容器进行排序,就是线性的(如vector,list,deque)。map也是一个集合容器,它里面存储的元素是pair,但是它不是线性存储的(前面提过,像红黑树),所以利用sort不能直接和map结合进行排序。需要将map转为vector。

        参考博客:http://www.cnblogs.com/lakeone/p/5599047.html

          3.对排序后的map取键并相应的频次-1。

class Solution {
public:
    static bool isless(const pair<char,int> l, const pair<char,int> r)  //静态成员函数???
    {
    	return l.second > r.second;
    }
    string frequencySort(string s) {
        map<char,int> strMap;
        for(auto ch:s)
        {
            strMap[ch]++;
        }
        vector<pair<char, int>> vecMap(strMap.begin(), strMap.end());  //map按值排序
        sort(vecMap.begin(), vecMap.end(), isless);
        
        string outstr;
        for (auto temp:vecMap)
        {
        	while (temp.second)
        	{
        		outstr += temp.first;   //map取键
        		temp.second--;
        	}	
        }
        return outstr;
        
    }
};


二、总结。

       使用二元谓词的时候必须得用静态成员函数。关于静态成员函数记录两个博客:

       http://blog.csdn.net/morewindows/article/details/6721430

       http://blog.csdn.net/kerry0071/article/details/25741425/

       至于为啥使用静态成员函数,请查看

       http://blog.csdn.net/xiaxzhou/article/details/71440464

     可以使用lamda表达式也很方便。

    

 
sort(vecMap.begin(), vecMap.end(), [](const pair<char, int> l, const pair<char, int> r){return l.second > r.second; }/*isless*/);

三、思路2

思路:一个直观的思路是先统计每个字符的数量,然后将这些字符连同频率放入一个优先队列中,再取出来即可.这种时间复杂度为O(n) + O(m log m),其中n为字符串长度,m为不同字符的个数,在最坏情况下时间复杂度为O(n log n),即所有字符都不一样.

注意优先队列的使用,包含头文件<queue>

string frequencySort(string s) {
	map<char, int> strMap;
	for (auto ch : s)
	{
		strMap[ch]++;
	}
	
	priority_queue<pair<int, char>> priQue;
	for (auto tempMap:strMap)
	{
		priQue.push(make_pair(tempMap.second, tempMap.first));
	}
	string outstr;
	while(!priQue.empty())
	{
		pair<int, char> temp = priQue.top();
		outstr.append(temp.first, temp.second);
		priQue.pop();
	}
	return outstr;

}


其实我们还有一种可以优化的方法,在统计完字符频率之后利用类似与计数排序的方法,开一个n+1长度大小的数组,将不同的频率字符放到频率的索引处.然后从高到低取得所有字符串.这种方法的好处是在最环情况下依然可以保证时间复杂度为O(n).

string frequencySort(string s) {
	unordered_map<char, int> freq;
	vector<string> bucket(s.size() + 1, "");
	string res;

	//count frequency of each character
	for (char c : s) freq[c]++;
	//put character into frequency bucket
	for (auto& it : freq) {
		int n = it.second;
		char c = it.first;
		bucket[n].append(n, c);  //bucket中加入n个c
	}
	//form descending sorted string
	for (int i = s.size(); i > 0; i--) {
		if (!bucket[i].empty())
			res.append(bucket[i]);
	}
	return res;
}

回顾知识点:最小堆

既然出现从大到小打印,那么就有可能是从小到大打印,除了将map转成vector,调用默认的sort函数排序之外,还有就是优先队列是按照最小堆建立的。

对于内置类型的最大堆,最小堆建立方法:

	//默认最大堆的建立 打印输出89,67,36,23,12,4,1
        vector<int> num = { 4, 23, 67, 12, 1, 36, 89 };
	priority_queue<int> test1(num.begin(), num.end());
	while (!test1.empty())
	{
		cout << test1.top() << " ";
		test1.pop();
	}
	cout << endl;

       //最小堆的建立包含<functional>,声明方式的改变,输出1,4,12,23,36,67,89
       priority_queue<int, vector<int>, greater<int>> test(num.begin(), num.end());
	while (!test.empty())
	{
		cout << test.top()<<" ";
		test.pop();
	}

也可使用multiset<int,greater<int>>,按照key由大到小排序

cout << endl;
	multiset<int, greater<int>> myset(num.begin(), num.end());
	for_each(myset.begin(), myset.end(), [](const int& out){cout << out << " "; });

完整的最小堆,从小到大频率输出字符

struct cmp
{
	bool operator()(const pair<int, char>&l, const pair<int, char>&r)
	{
		return l.first > r.first;
	}

};

string frequencySort(string s) {
	map<char, int> strMap;
	for (auto ch : s)
	{
		strMap[ch]++;
	}
        //注意定义的方式,同时自定义第三个函数
	priority_queue<pair<int, char>, vector<pair<int, char>>, cmp> priQue;
	for (auto tempMap : strMap)
	{
		priQue.push(make_pair(tempMap.second, tempMap.first));
	}
	string outstr;
	while (!priQue.empty())
	{
		pair<int, char> temp = priQue.top();
		outstr.append(temp.first, temp.second);
		priQue.pop();
	}
	return outstr;
	return 0;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值