题目描述:
给一非空的单词列表,返回前 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 次。
注意:
假定 k 总为有效值, 1 ≤ k ≤ 集合元素数。
输入的单词均由小写字母组成。
扩展练习:
尝试以 O(n log k) 时间复杂度和 O(n) 空间复杂度解决。
emm使用笨方法
用map按照value进行排序,比较烂的方法
class Solution {
public List<String> topKFrequent(String[] words, int k) {
List<String> result = new ArrayList<>(k);
if (k == words.length) {
for (String string : words) {
result.add(string);
}
Collections.sort(result);
return result;
} else {
Map<String, Integer> map = new TreeMap<String, Integer>();
for (String string : words) {
map.put(string,map.getOrDefault(string, 0) + 1);
}
List<Map.Entry<String, Integer>> list = map.entrySet().stream()
.sorted((entry1, entry2) -> entry2.getValue().compareTo(entry1.getValue()))
.collect(Collectors.toList());
int index = 0;
for(Map.Entry<String,Integer> mapping:list){
if(index ++ < k){
result.add(mapping.getKey());
}else {
break;
}
}
return result;
}
}
}
看看别人使用前缀树如何实现的
/**
* 使用前缀树
*/
class MagicDictionary {
class PreTree {
public char value;//当前前缀树的节点内容---字符
public int count;//以当前前缀树节点结尾的字符串的计数
public HashMap<Character, PreTree> subTree;//当前前缀树的子节点
public PreTree(char v) {
this.value = v;
this.count = 0;
this.subTree = new HashMap<>();
}
public void buildTree(char[] strs, int index, PreTree root) {
int len = strs.length;
if (len == 0) {
return;
}
if (index == len) {
root.count++;
return;
}
if (!root.subTree.containsKey(strs[index])) {
PreTree node = new PreTree(strs[index]);
root.subTree.put(strs[index], node);
}
buildTree(strs, index + 1, root.subTree.get(strs[index]));
}
}
public PreTree root = null;
/**
* Initialize your data structure here.
*/
public MagicDictionary() {
root = new PreTree(' ');
}
/**
* Build a dictionary through a list of words
*/
public void buildDict(String[] dict) {
int len = dict.length;
for (int i = 0; i < len; i++) {
root.buildTree(dict[i].toCharArray(), 0, root);
}
}
/**
* Returns if there is any word in the trie that equals to the given word after modifying exactly one character
*/
public boolean search(String word) {
if (subSearch(root, word.toCharArray(), 0, 0) == 1)
return true;
else
return false;
}
/**
* @param root
* @param str
* @param index
* @param flag 当前状态是不是已经又字符改变过了,0:没变过,1:已经有一个字符改变过了
* @return 是否找到正确解,,1:找到,0:没找到
*/
public int subSearch(PreTree root, char[] str, int index, int flag) {
if (str.length == 0)
return 0;
char currChar = str[index];
if (index == str.length - 1) {
if (flag == 0) {//之前没有更换过字符
for (char i = 'a'; i <= 'z'; i++) {
if (i != currChar) {
if (root.subTree.containsKey(i) && root.subTree.get(i).count > 0) return 1;
} else continue;
}
return 0;
} else {//之前更换过
if (root.subTree.containsKey(currChar) && root.subTree.get(currChar).count > 0) return 1;
else return 0;
}
}
if (flag == 0) {//之前没有换过字符
//更换个当前字符试试(虽然是“更换”了当前字符,,但是并没有字符数组中改变任何值)
for (char i = 'a'; i <= 'z'; i++) {
if (currChar != i) {
if (root.subTree.containsKey(i)
&& subSearch(root.subTree.get(i), str, index + 1, 1) == 1)
return 1;
} else continue;
}
//保持当前字符不变
if (root.subTree.containsKey(currChar)) {
if (subSearch(root.subTree.get(currChar), str, index + 1, 0) == 1) return 1;
}
} else {//之前换过字符
if (!root.subTree.containsKey(currChar)) {
return 0;
} else {
return subSearch(root.subTree.get(currChar), str, index + 1, 1);
}
}
return 0;
}
}
class Solution {
public List<String> topKFrequent(String[] words, int k) {
if (words.length == 0) return new ArrayList<>();
Map<String, Integer> freqMap = new HashMap<>();
for (String word : words) {
freqMap.put(word, freqMap.getOrDefault(word, 0) + 1);
}
// 创建按照频率区分的桶,桶的大小为单词数量大小+1(bucket[0]肯定没有数据),即假设所有单词的频率都一样
List<String>[] buckets = new List[words.length + 1];
// 给桶中放入数据,单词的频率即桶的下标,故桶天然已经排好顺序
for (Map.Entry<String, Integer> entry : freqMap.entrySet()) {
int freq = entry.getValue();
String word = entry.getKey();
if (buckets[freq] == null) {
buckets[freq] = new ArrayList<>();
}
buckets[freq].add(word);
}
List<String> result = new ArrayList<>();
for (int i = buckets.length - 1; i >= 0 && k > 0; i--) {
if (buckets[i] == null) continue;
// 给单词排序
Collections.sort(buckets[i]);
List<String> temp = buckets[i].subList(0, Math.min(buckets[i].size(), k));
result.addAll(temp);
k -= temp.size();
}
return result;
}
}