zoukankan      html  css  js  c++  java
  • 基本排序算法之桶排序(力扣451题、347题)

    桶排序是对整数进行排序的高效算法,在进行桶排序的时候我们需要先确定key,即key代表得含义,以及key的取值范围,key的取值范围决定了桶的数量。假设键值的范围是从0到t,那么需要t+1个桶,标记分别为0、1、……、t 。如果元素的键值是i,那么就将该元素放入桶i中,每个桶放的都是键值相同的元素。

    一般使用一个ArraysList数组作为一组不同标记的桶。桶中存储的正是键值相同的一系列元素。伪代码如下:

        public void bucketsort(E[] list){
            
            ArrayList[] bucket = new ArrayList[t+1];
    
            for (int i = 0; i < list.length; i++) {
                int key = list[i].getKey();
                
                if (bucket[key] == null){
                    bucket[key] = new ArrayList<>();
                }
                bucket[key].add(list[i]);
            }
            
            int k = 0;
            for (int i = 0; i < bucket.length; i++) {
                if (bucket[i]!=null){
                    for (int j = 0; j < bucket[i].size(); j++) {
                        list[k++] = bucket[i].get(j);
                    }
                }
            }
            
        }

    桶排序的时间复杂度O(n+t),空间复杂度为O(n+t),n为元素列表的大小,t为桶的大小

    练习:

    1、力扣第451题

      给定一个字符串,请将字符串里的字符按照出现的频率降序排列。

    分析思路:

      将字符串中出现频率最高的字符放在最前边,字符出现的频率的大小为1-n,所以以字符出现的频数作为桶的标记,将频数出现相同的放在一个桶内,有一个细节就是如果同一个字符,如果出现的频数为i,那么就将它放入桶中i个,这样方便后面求出最终的排列结果。最后,倒序遍历桶,然后依次拼接字符串。

    具体的代码如下:

    public String frequencySort(String s) {
            if (s.length() <=2){
                return s;
            }
            HashMap<Character, Integer> map = new HashMap<>();
            for (char c : s.toCharArray()) {
                map.put(c,map.getOrDefault(c,0)+1);
            }
    
            ArrayList[] bucket = new ArrayList[s.length() + 1];
    
            for (Character c : map.keySet()) {
                int count = map.get(c);
                if (bucket[count] == null){
                    bucket[count] = new ArrayList<>();
                }
                if (count>1){
                    for (int i = 0; i < count; i++) {
                        bucket[count].add(c);
                    }
                }else {
                    bucket[count].add(c);
                }
    
            }
    
            char[] res = new char[s.length()];
            int k = 0;
            for (int i = bucket.length-1; i >= 0; i--) {
                if (bucket[i] == null){
                    continue;
                }else {
                    for (int j = 0; j < bucket[i].size(); j++) {
                        res[k++] = (Character)bucket[i].get(j);
                    }
                }
            }
    
            return new String(res);
    
        }

    2、力扣第347题

      给定一个非空的整数数组,返回其中出现频率前 高的元素。

        你可以假设给定的 k 总是合理的,且 1 ≤ k ≤ 数组中不相同的元素的个数。
        你的算法的时间复杂度必须优于 O(n log n) , n 是数组的大小。
        题目数据保证答案唯一,换句话说,数组中前 k 个高频元素的集合是唯一的。
        你可以按任意顺序返回答案。

    分析思路:

      要求求出出现频率最高的前K个元素,那么说明数组中元素的频数至少为1,至多为n(假设数组一共n个元素),那么我们可以以元素出现的频数作为键值进行桶排序,设t为数组不重复元素的个数,那么需要的桶的标记数量就为t+1,每个桶中存储的元素就是频度相同的元素。最后我们从后向前遍历桶,求出k个不同元素即可。

    参考自:https://github.com/CyC2018/CS-Notes/      (膜拜大神)

    实现代码如下:

        public int[] topKFrequent(int[] nums, int k) {
            if (nums == null){
                return null;
            }
            HashMap<Integer, Integer> map = new HashMap<>();
            int n = nums.length;
            for (int num : nums) {
                if (map.get(num) == null){
                    map.put(num,1);
                }else {
                    int count = map.get(num);
                    count ++;
                    map.put(num,count);
                }
            }
            // 用元素出现的频数作为key,key的范围是0-t,所以需要t+1个桶,标记从0-t
            ArrayList[] bucket = new ArrayList[n + 1];
            // 将频度相同的元素添加到相同的水桶中
            for (Integer key : map.keySet()) {
                int count = map.get(key);
                if (bucket[count] == null){
                    bucket[count] = new ArrayList<>();
                }
                bucket[count].add(key);
            }
            // 进行寻找频率前k高的元素
            ArrayList<Integer> res = new ArrayList<>();
            for (int i = bucket.length-1; i >=0; i--) {
                if (bucket[i] == null){
                    continue;
                }else {
                    if (bucket[i].size() <= (k-res.size())){
                        res.addAll(bucket[i]);
                    }else {
                        res.addAll(bucket[i].subList(0,k-res.size()));
                    }
                }
            }
            return res.stream().mapToInt(Integer::valueOf).toArray();
        }
  • 相关阅读:
    Atitit.ati orm的设计and架构总结 适用于java c# php版
    Atitit.ati dwr的原理and设计 attilax 总结 java php 版本
    Atitit.ati dwr的原理and设计 attilax 总结 java php 版本
    Atitit. 软件设计 模式 变量 方法 命名最佳实践 vp820 attilax总结命名表大全
    Atitit. 软件设计 模式 变量 方法 命名最佳实践 vp820 attilax总结命名表大全
    Atitit 插件机制原理与设计微内核 c# java 的实现attilax总结
    Atitit 插件机制原理与设计微内核 c# java 的实现attilax总结
    atitit.基于  Commons CLI 的命令行原理与 开发
    atitit.基于  Commons CLI 的命令行原理与 开发
    atitit.js 与c# java交互html5化的原理与总结.doc
  • 原文地址:https://www.cnblogs.com/yxym2016/p/12952987.html
Copyright © 2011-2022 走看看