描述
给定一个字符串数组,再给定整数k,请返回出现次数前k名的字符串和对应的次数。
返回的答案应该按字符串出现频率由高到低排序。如果不同的字符串有相同出现频率,按字典序排序。
对于两个字符串,大小关系取决于两个字符串从左到右第一个不同字符的 ASCII 值的大小关系。
比如"ah1x"小于"ahb","231"<”32“
字符仅包含数字和字母
[要求]
如果字符串数组长度为N,时间复杂度请达到O(NlogK)
第一种解法:现存入HashMap,此时时间复杂度为O(N),再将HashMap转为List进行排序,此时时间复杂度O(nlogn),最后取出k个元素,所以总的时间复杂度为O(nlogn)。
public class Solution {
/**
* return topK string
* @param strings string字符串一维数组 strings
* @param k int整型 the k
* @return string字符串二维数组
*/
public String[][] topKstrings (String[] strings, int k) {
// write code here
Map<String, Integer> map = new HashMap<>();
for(int i=0;i<strings.length;i++){
if(map.get(strings[i]) == null){
map.put(strings[i], 1);
}else{
map.put(strings[i], map.get(strings[i]) + 1);
}
}
Set<Map.Entry<String, Integer>> set = map.entrySet();
List<Map.Entry<String, Integer>> list = new ArrayList(set);
Collections.sort(list, new MyCompare());
String[][] res = new String[k][2];
for(int i=0;i<k;i++){
res[i][0] = list.get(i).getKey();
res[i][1] = String.valueOf(list.get(i).getValue());
}
return res;
}
class MyCompare implements Comparator<Map.Entry<String, Integer>>{
@Override
public int compare(Map.Entry<String, Integer> entry1, Map.Entry<String, Integer> entry2){
int res = entry2.getValue().compareTo(entry1.getValue());
if(res == 0){
return entry1.getKey().compareTo(entry2.getKey());
}
return res;
}
}
}
可以使用lambda表达式进行优化
import java.util.*;
public class Solution {
/**
* return topK string
* @param strings string字符串一维数组 strings
* @param k int整型 the k
* @return string字符串二维数组
*/
public String[][] topKstrings (String[] strings, int k) {
// write code here
Map<String, Integer> map = new HashMap<>();
for(int i=0;i<strings.length;i++){
if(map.get(strings[i]) == null){
map.put(strings[i], 1);
}else{
map.put(strings[i], map.get(strings[i]) + 1);
}
}
Set<Map.Entry<String, Integer>> set = map.entrySet();
List<Map.Entry<String, Integer>> list = new ArrayList(set);
Collections.sort(list, (entry1, entry2) -> {
int res = entry2.getValue().compareTo(entry1.getValue());
if(res == 0){
return entry1.getKey().compareTo(entry2.getKey());
}
return res;
});
String[][] res = new String[k][2];
for(int i=0;i<k;i++){
res[i][0] = list.get(i).getKey();
res[i][1] = String.valueOf(list.get(i).getValue());
}
return res;
}
}
上面的写法,要想到将HashMap转为元素为Map.Entry的List。然后进行排序处理。但是这种方式时间复杂度是nlogn。
第二种解法,Topk的问题肯定会想到使用堆来解决,但是要注意如果是取Topk小值,此时使用大顶堆,如果是取Topk大值,此时使用小顶堆。这和直观上的理解有所区别。这里为了方便使用PriorityQueue来设计一个小顶堆。
代码实现:
import java.util.*;
public class Solution {
/**
* return topK string
*
* @param strings string字符串一维数组 strings
* @param k int整型 the k
* @return string字符串二维数组
*/
public String[][] topKstrings(String[] strings, int k) {
// write code here
if (k == 0) {
return new String[][]{};
}
String[][] res = new String[k][2];
Map<String, Integer> map = new HashMap<>();
// 统计各个字符串出现的次数
for (int i = 0; i < strings.length; ++i) {
String s = strings[i];
if (!map.containsKey(s)) {
map.put(s, 1);
} else {
map.put(s, map.get(s) + 1);
}
}
Comparator<Map.Entry<String, Integer>> comparator = (k1, k2) -> {
Integer tmp = k1.getValue() - (k2.getValue());
if (tmp.intValue() != 0) {
return tmp;
}
return k2.getKey().compareTo(k1.getKey());
};
PriorityQueue<Map.Entry<String, Integer>> priorityQueue = new PriorityQueue<>(k, comparator);
map.entrySet().forEach(entry -> {
if (priorityQueue.size() < k) {
priorityQueue.offer(entry);
} else if (comparator.compare(priorityQueue.peek(), entry) < 0) {
priorityQueue.poll();
priorityQueue.offer(entry);
}
});
String[][] result = new String[k][2];
for (int j = k - 1; j >= 0; j--) {
Map.Entry<String, Integer> element = priorityQueue.poll();
result[j][0] = element.getKey();
result[j][1] = element.getValue().toString();
}
return result;
}
}
参考:
堆结构的优秀实现类----PriorityQueue优先队列_Single_YAM的博客-CSDN博客_priorityqueue
Java使用PriorityQueue建立大小顶堆_学而不思则忘的博客-CSDN博客_java priorityqueue大顶堆小顶堆
本文介绍了一种优化的算法,通过HashMap统计字符串出现次数,利用PriorityQueue实现时间复杂度为O(NlogK)的Top K 字符串和出现次数的查找,适用于字符串数组查询。作者提供了两种解决方案并对比了其性能。

2031

被折叠的 条评论
为什么被折叠?



