给一非空的单词列表,返回前 k 个出现次数最多的单词。
返回的答案应该按单词出现频率由高到低排序。如果不同的单词有相同出现频率,按字母顺序排序。
示例 1:
输入: ["i", "love", "leetcode", "i", "love", "coding"], k = 2
输出: ["i", "love"]
解析: "i" 和 "love" 为出现次数最多的两个单词,均为2次。
注意,按字母顺序 "i" 在 "love" 之前。
示例 2:
输入: ["the", "day", "is", "sunny", "the", "the", "the", "sunny", "is", "is"], k = 4
输出: ["the", "is", "sunny", "day"]
解析: "the", "is", "sunny" 和 "day" 是出现次数最多的四个单词,
出现次数依次为 4, 3, 2 和 1 次。
思路
这题主要就是个排序的问题,感觉用C/C++混合的方式写起来会很方便,可以用algorithm
里的sort
函数排序,java里得重写compare
函数,而且返回值容易让人弄不清楚。
我这里是这么理解的,假设元素o1
在前,o2
在后:
- 如果
return 1
,就说明o2
和o1
要交换位置,变成o2
在前,o1
在后; - 如果
return -1
,就说明o1
和o2
保持原位,仍然是o1
在前,o2
在后; - 如果
return 0
,就说明o1==o2
回到这题,因为是要找前k
个频率最高的单词,很明显是要建立一个关于频率的大顶堆,然后取出前k
个堆顶元素即可。我这里是写了一个Word
类来绑定字符串和出现频率之间的关系,因此,建立的大顶堆里面放的元素也应该是Word
类型的。
接下来的步骤就很简单了。主要是compare
函数,因为题目要求如果有相同频率,必须按字典序升序,因此,在compare
里还应该判断,当频率相同时,直接返回o1.val.compareTo(o2.val)
即可,默认即为字典序升序排列。
代码
public class Solution {
class Word{
String val;
int fre;
Word(String val, int fre){
this.val = val;
this.fre = fre;
}
}
public List<String> topKFrequent(String[] words, int k){
int n = words.length;
Map<String, Integer> map = new HashMap<String, Integer>();
for(String x : words) {
if(map.get(x)==null) {
map.put(x, 1);
}
else {
int val = map.get(x);
val++;
map.put(x, val);
}
}
PriorityQueue<Word> maxHeap = new PriorityQueue<Word>(n, new Comparator<Word>() {
@Override
public int compare(Word o1, Word o2) {
if(o1.fre!=o2.fre) {
if(o1.fre<o2.fre) return 1;
else if(o1.fre>o2.fre) return -1;
else return 0;
}
else {
return o1.val.compareTo(o2.val);
}
}
});
List<Word> list = new ArrayList<Word>();
for(String x : map.keySet()) {
Word tempWord = new Word(x, map.get(x));
list.add(tempWord);
}
for(Word x : list) {
maxHeap.offer(x);
}
List<String> result = new ArrayList<String>();
for(int i=0;i<k;i++) {
Word maxFre = maxHeap.poll();
result.add(maxFre.val);
}
return result;
}
}