先上答题截图,在写思路,哈哈哈哈啊
给定一个字符串,请将字符串里的字符按照出现的频率降序排列。
示例 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上根据键和值的排序语法。
老实交代解题代码是抄官方题解的,因为我想到思路但是不会java中关于map键值排序的那部分语法,所以下面来总结了。
关于map中对 map的values进行排序
第一种方法:最简洁
一上面的这个力扣题为例可以先建立一个键为 Character 类型 值为 Integer 类型的 HashMap,然后使用 List 集合去存储 map里面的键,最后使用简洁的 lambda表达式 语法进行排序,也是上面的给的那种形式
Map<Character, Integer> map = new HashMap<Character, Integer>();
for (int i = 0; i < s.length(); ++i) map.put(s.charAt(i), map.getOrDefault(s.charAt(i), 0) + 1);
List<Character> list = new ArrayList<Character>(map.keySet());
Collections.sort(list, (a, b) -> map.get(b) - map.get(a));
这里对上面的代码进行一些解释(仅对于可能是新手入门算法,虽然我也是新手不算入门,哈哈哈哈哈 >=<),因为我之前刚开始刷题的时候很多东西看不懂,很是头疼,经常要百度很多函数的用法,所以。。。。。。。很能理解那种烦躁的心情,正好今天没事顺便来写点
Character,Integer 首先Map 或者 List这样的容器里面只能放非简单基本类型的变量所以这里面不能用char 和 int, 第二点就是s.charAt(i) 是取了字符串s中的 index为 i 位置的字符, map.getOrDefault(s.charAt(i), 0)函数是如果没在map中找到s.charAt(i) 字符的键的话,就设置这个字符的键的值为默认0,如果找到了就返回原本在map中s.charAt(i)字符对应的值。第三个一般对于容器来说排序用的 Collections.sort() 函数,而对于其他一般基本类型的数组,如 int [ ] 则使用Arrays.sort()函数, 最后 (a, b)-> map.get(b) - map.get(a) 是属于lambda表达式语法,这个语法如果不懂建议需要百度一下,这上面的使用 map.get(b) - map.get(a) 的作用是进行降序排序,如果要进行升序排序的话需要把a和b换一个位置 ,换成 map.get(a) - map.get(b)
第二种方法:比较常规
这种不通过使用最新的lambda表达式语法去进行排序,而是使用最常规传统的改写compare()函数的方法,不过这里又用了另外一种java的比较新的语法,匿名类(如果有看不懂或者看不习惯这中语法的朋友建议去百度学习一下或者可以自己重写类去实现Comparator接口并且改写里面的compare()函数这个方法大概代码我会放在下面介绍
Map<Character, Integer> map = new HashMap<Character, Integer>();
for (int i = 0; i < s.length(); ++i) map.put(s.charAt(i), map.getOrDefault(s.charAt(i), 0) + 1);
List<Character> list = new ArrayList<Character>(map.keySet());
Collections.sort(list, new Comparator<Character>(){
public int compare(Character a, Character b){
return map.get(b) - map.get(a);
}
});
这种方法和第一种方法的不懂只在于重写排序的时候第一种方法使用lambda语法实现的这种是用匿名类实现的。
第三种方法: 更传统
新建类实现Comparator接口重写compare()函数去实现
public class SortMapByValue {
public static Map<K, V> sortMap(Map<K, V> unsortedMap) {
Comparator<K> comparator = new ValueComparator<K, V>(unsortedMap);
TreeMap<K, V> result = new TreeMap<K, V>(comparator);
result.putAll(unsortedMap);
return result;
}
}
class ValueComparator<K, V extends Comparable<V>> implements Comparator<K> {
HashMap<K, V> map = new HashMap<K, V>();
public ValueComarartor(HashMap<K, V> map) {
this.map.putAll(map);
}
@Override
public int compare(K s1, K s2) {
return map.get(s1).compareTo(map.get(s2));
}
}
上面代码只是作为摸板仅作参考
当然出了针对这个力扣题可以使用更轻量的List<Character> 更多情况还可以直接使用传入整个map去进行重写排序函数
Map<Character, Integer> map = new HashMap<Character, Integer>();
for (int i = 0; i < s.length(); ++i) map.put(s.charAt(i), map.getOrDefault(s.charAt(i), 0) + 1);
List<Map.Entry<Character, Integer>> list = new ArrayList<Map.Entry<Character, Integer>>(map.entrySet());
Collections.sort(list, new Comparator<Map.Entry<Character, Integer>>(){
public int compare(Map.Entry<Character, Integer> a, Map.Entry<Character, Integer> b){
return b.getValue() - a.getValue();
}
});
这种方法相对于上面比较就时间和空间而言过于厚重,能使用上面的方法时建议使用上对面的那些方法
最后说一下重写compare( ) 函数时除了这种数值型的可以直接用 “ - ”减号这个运算符去实现,更多时候还可以用 compareTo( ) 这个函数去实现,而且这个函数不仅可以用于数值型的参数还对于许多非数值型的参数类型也可以做比较,当然具体的用法的话如果不熟悉还是建议大家百度一下
这里举一下对于方法一种map.get(b) - map.get(a) 其实与使用map.get(b).compareTo(map.get(a))的效果是一样的。
最后先写到这里,下午写了一下午,然后刚才屏幕熄屏了,怎么都打不开,下的我以为要强制关机,幸好没有,但是打开的时候电脑网断了,浏览器也自己掉了,吓得我人都傻了,幸好这个服务器上面有草稿记录,不然真的一下午白费了,这个真的不错,最后收尾了,我要特别强调一句,我的水平不高,文章中有些错的地方欢迎各位大佬们评论指导订正,我看到一定去学习并改正,最后特别感谢各位读者大佬们的观看,谢谢,也希望你们辛苦的阅读时间能有所收获,祝读者大佬门学习开心 > = <