题目描述:
给定一个字符串,请将字符串里的字符按照出现的频率降序排列。
示例 1:
输入: "tree" 输出: "eert" 解释: 'e'出现两次,'r'和't'都只出现一次。 因此'e'必须出现在'r'和't'之前。此外,"eetr"也是一个有效的答案。
示例 2:
输入: "cccaaa" 输出: "cccaaa" 解释: 'c'和'a'都出现三次。此外,"aaaccc"也是有效的答案。 注意"cacaca"是不正确的,因为相同的字母必须放在一起。
示例 3:
输入: "Aabb" 输出: "bbAa" 解释: 此外,"bbaA"也是一个有效的答案,但"Aabb"是不正确的。 注意'A'和'a'被认为是两种不同的字符。
这道题也是用map来操作,具体思路是,将字符和字符出现的数量保存到map,键为字符,值为出现的次数。然后对map进行排序(按值排序),然后遍历map,将对应的键(排好序的)拼接起来这个就是最后的字符串,按照字符出现的次数进行排序。
本题的思路很好理解,重点就是排序,因为map没有按照值排序的方法,这个怎么办呢?java有一个比较器,但要求的参数是list,那么我们可以通过Arraylist构造函数把map.entrySet()转化为list,这样就可以用比较器进行比较了。(这个解决了也就完成了)最后就剩下字符串的拼接了,用到stringbuilder,当然stringbuffer也可以。
具体代码如下:
String s = "tree";
// 本题重点在于排序,将字符和出现次数放到map,中,对map排序,进行字符串拼接即可
char []ch = s.toCharArray ();
// 查找表(将数据存到一个表里,然后用去查找)问题首先想到map,map查找比list更优(更适合查找)
Map<Character,Integer> map = new HashMap <> ( );
for (int i = 0;i<ch.length;i++){
if (map.containsKey ( ch[i] ) ){
map.put ( ch[i],map.get ( ch[i] )+1 );
}else {
map.put ( ch[i],1 );
}
}
// 通过Arraylist构造函数吧map.entrySet()转化为list(map没有按值排序的方法,我们要把map转化为list,用比较器进行排序,map是无序的,在空间上的无序)
List<Map.Entry<Character,Integer>> list = new ArrayList <> ( map.entrySet () );
// 通过比较器进行比较排序
Collections.sort ( list , new Comparator <Map.Entry <Character, Integer>> ( ) {
@Override
public int compare( Map.Entry <Character, Integer> o1 , Map.Entry <Character, Integer> o2 ) {
// 逆序排序(从大到小),要顺序排序,o1-o2
return o2.getValue () -o1.getValue() ;
}
} );
// 用字符串类StrinBuilder(非线程安全,不支持并发),用来拼接(操作)字符串
StringBuilder sb = new StringBuilder ();
// 将排好序的列表遍历,得到排好序的集合,然后按值遍历,将键加入sb中,最后输出(集合的遍历,最优方法,entry)
for (Map.Entry<Character, Integer> map1 :list){
// 对每一个值进行遍历,例如e - 2,遍历两次,将e添加进去,t出现1词,遍历1次,将t添加进去。
for (int i =0;i<map1.getValue ();i++){
System.out.println(map1.getKey ());
sb.append ( map1.getKey () );
}
}
System.out.println(sb.toString ());
执行结果:
执行用时:
总结:这道题也是 map的用法,思路很明确,重点在于map的排序,用比较器进行排序。这个得注意注意
2019-3-19