【leetcode】出现频率最高的 k 个数字

comparingInt
ComInt

一、题目描述

给定一个整数数组 nums 和一个整数 k ,请返回其中出现频率前 k 高的元素。可以按 任意顺序 返回答案。

输入: nums = [1,1,1,2,2,3], k = 2
输出: [1,2]

二、代码思路

想想可以使用什么数据结构

1、HashMap可以保存键和值(值存放次数),但是没有排序功能。我们还得全部取出遍历。

2、TreeSet可以排序但是只有单键

3、TreeMap 也不太行

4、可以使用小根堆(优先级队列)试试

其实,其本质是TopK问题,针对TopK问题,使用优先级队列是比较好用的。

优先级队列:https://blog.csdn.net/BillieFan/article/details/107578057

所谓优先级队列,就是为了找到最值而产生的数据结构。

三、代码题解
package leetcode;

import java.util.*;

/*
 * @author lzy
 * @version 1.0
 * */
public class topK {
    public static void main(String[] args) {
        int arr[] = {1,1,1,2,2,3};
        int k = 2;
        topK topK = new topK();
        topK.topKFrequent(arr, k);
    }
    public int[] topKFrequent(int[] nums, int k) {
        //想想可以使用什么数据结构
        //1、HashMap可以保存键和值(值存放次数),但是没有排序功能。我们还得全部取出遍历。
        //2、TreeSet可以排序但是只有单键
        //3. TreeMap 也不太行
        //4、可以使用小根堆试试
        TreeMap<Integer,Integer> map = new TreeMap(new Comparator() {
            @Override
            public int compare(Object o1, Object o2) {
                return 0;
            }
        });
        HashMap<Integer,Integer> map1 = new HashMap();
        //k作为键 出现次数作为值
        for (int item : nums) {
            map1.put(item,map1.getOrDefault(item,0) + 1);
        }
        //使用小根堆
        PriorityQueue<int[]> pq1 = new PriorityQueue<>((a, b) -> a[1] - b[1]);
        PriorityQueue<int[]> pq = new PriorityQueue<>(Comparator.comparingInt(a -> a[1]));
        PriorityQueue<int[]> queue1 = new PriorityQueue<int[]>(new Comparator() {
            @Override
            public int compare(Object o1, Object o2) {
                return 0;
            }
        });
        PriorityQueue<int[]> queue = new PriorityQueue<>((a, b) -> a[1] - b[1]);
        //遍历HashMap将其中存放的键值放入优先级队列,利用优先级队列的特点选出前K个元素
        for (Map.Entry<Integer, Integer> item : map1.entrySet()) {
            //将key 和 value 放入数组,然后再将数组放入优先级队列进行排序,排序的手段是根据数据的arr[1]来比较的,也就是出现次数
            int arr[] = {item.getKey(), item.getValue()};
            queue.offer(arr);
            //我们只需要找到前k个出现次数最多的即可,所以我们使用小根堆,根头永远放的次数最少的,所以一旦根堆size大于K,我们只需要把根头删掉即可。
            if (queue.size() > k) {
                queue.poll();
            }
        }
        int res[] = new int[k];
        for (int i = k - 1; i >= 0; i--) {
            //根堆中存放的元素是数组,我们只需要取出数组第1个元素即可。
            res[i] = queue.poll()[0];
        }
        return res;
    }
}

时间复杂度: nlogk

调整根堆的时间复杂度为树的高度 也就是logn

暴力解法:

用HashMao存key和出现次数,然后遍历 K次 HashMap ,依次找到 K 个最大的值。

public int[] topKFrequent(int[] nums, int k) {
        if (nums == null) {
            return new int[]{};
        }
        int length = nums.length;
        int[] answer = new int[k];
        HashMap<Integer, Integer> map = new HashMap<>(16);
        for (int i = 0; i < length; i++) {
            int num = nums[i];
            map.put(num, map.getOrDefault(num, 0) + 1);
        }
        for (int i = 0; i < k; i++) {
            int n = Integer.MIN_VALUE;
            int count = 0;
            for (Integer number : map.keySet()) {
                if (map.get(number) > count) {
                    count = map.get(number);
                    n = number;
                }
            }
            map.put(n, 0);
            answer[i] = n;
        }
        return answer;
    }
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
题目描述: 给定一个字符串,请将字符串里的字符按照出现频率降序排列。 示例 1: 输入: "tree" 输出: "eert" 解释: 'e'出现两次,'r'和't'都只出现一次。因此'e'必须出现在'r'和't'之。此外,"eetr"也是一个有效的答案。 示例 2: 输入: "cccaaa" 输出: "cccaaa" 解释: 'c'和'a'都出现三次。此外,"aaaccc"也是有效的答案。注意"cacaca"是不正确的,因为相同的字母必须放在一起。 示例 3: 输入: "Aabb" 输出: "bbAa" 解释: 此外,"bbaA"也是一个有效的答案,但"Aabb"是不正确的。注意'A'和'a'被认为是两种不同的字符。 Java代码如下: ``` import java.util.*; public class Solution { public String frequencySort(String s) { if (s == null || s.length() == 0) { return ""; } Map<Character, Integer> map = new HashMap<>(); for (int i = 0; i < s.length(); i++) { char c = s.charAt(i); map.put(c, map.getOrDefault(c, 0) + 1); } List<Map.Entry<Character, Integer>> list = new ArrayList<>(map.entrySet()); Collections.sort(list, (o1, o2) -> o2.getValue() - o1.getValue()); StringBuilder sb = new StringBuilder(); for (Map.Entry<Character, Integer> entry : list) { char c = entry.getKey(); int count = entry.getValue(); for (int i = 0; i < count; i++) { sb.append(c); } } return sb.toString(); } } ``` 解题思路: 首先遍历字符串,使用HashMap记录每个字符出现次数。然后将HashMap转换为List,并按照出现次数从大到小进行排序。最后遍历排序后的List,将每个字符按照出现次数依次添加到StringBuilder中,并返回StringBuilder的字符串形式。 时间复杂度:O(nlogn),其中n为字符串s的长度。遍历字符串的时间复杂度为O(n),HashMap和List的操作时间复杂度均为O(n),排序时间复杂度为O(nlogn),StringBuilder操作时间复杂度为O(n)。因此总时间复杂度为O(nlogn)。 空间复杂度:O(n),其中n为字符串s的长度。HashMap和List的空间复杂度均为O(n),StringBuilder的空间复杂度也为O(n)。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值