用Java实现求一个数组中的出现次数最多的元素的个数

前些天做笔试题的时候,遇到这一道题:用Java实现求一个数组中的出现次数最多的元素的个数。但是时间比较紧,我想出了先排序,然后遍历一遍,相邻元素相等则累计,不同则重新累计,遍历完就可以得到相同元素出现最多的元素。自认为还可以,不过面试官笑着对我说:“加入数组的元素不能排序呢?”。哦,我把数组默认当做int数组了,假如数组是String类型的或者是其他的类型,就不能使用我这种方式了。

其实很容易想到一种方法,就是将相同的元素先各就各位,比如装在一个集合中,最后清点下哪个集合最大就可以了。为了使不同的类型数据可以复用,使用泛型(不过如果是基本类型数组就要转化为包装类型了):

/**
     * 使用ArrayList处理,如果是自己定义的类,则要合理重写equals方法
     * @param a
     * @return
     */
    public static <T> int getMostFrequentByArrayList(T a[]){
        if(a == null||a.length == 0){
            return 0;
        }
        int size  = a.length;
        int result = 0;
        //持有所有集合的集合。指定容量以免扩容带来的性能消耗,不过可能浪费空间
        ArrayList<ArrayList<T>> severalTempList = new ArrayList<ArrayList<T>>(size);

        for (int i = 0; i < size; i++) {
            boolean isAdd = false;
            T t = a[i];
            //遍历severalTempList每个ArrayList,找到t所属的则添加上去
            for(int j = 0;j < severalTempList.size();j++){
                ArrayList<T> singleTemps = severalTempList.get(j);
                if(singleTemps != null){
                    if(t.equals(singleTemps.get(0))){
                        singleTemps.add(t);
                        isAdd = true;
                    }
                }
            }
            //找不到t所属的则创建新的ArrayList添加到severalTempList,并将t添加到新的ArrayList
            if(!isAdd){
                ArrayList<T> singleTemps = new ArrayList<T>();
                singleTemps.add(t);
                severalTempList.add(singleTemps);
            }
        }

        //经过拆分后长度最大的集合
        ArrayList<T> largestList = severalTempList.get(0);
        //从索引为1开始就可以了
        for(int i = 1;i < severalTempList.size();i++){
            //通过遍历找到元素最多的集合
            if(severalTempList.get(i).size() > largestList.size()){
                largestList = severalTempList.get(i);
            }

            result = largestList.size();
        }

        return result;

    }

嗯,只要数组的长度不超过int的上限就行。。

test:

public static void main(String[] args){
        Integer a[] = {1,1,5,8,6,9,4,7,5,2,6,5,8,5,5,8,6,2};
        String s[] = {"s","s","s","t","t","t","t","t","c"};
        int resultString = MostFrequent.getMostFrequentByArrayList(s);
        int resultInteger = MostFrequent.getMostFrequentByArrayList(a);

        System.out.println(resultInteger);
        System.out.println(resultString);

    }

结果:
5
5

嗯,看来Integer和String都没问题。

不过通过遍历ArrayList将各个元素分配到对应的集合中的办法略显臃肿,性能也不算高。我们知道HashMap查询速度最快,而且使用LinkedList进行添加操作可以避免扩容带来的性能开销。所以这时候可以使用HashMap和LinkedList进行下优化:

/**
     * 使用HashMap提高性能。如果是自己定义的类,则要合理重写hashCode和equals方法
     * @param a
     * @return
     */
    public static <T> int getMostFrequentByMap(T a[]){
        if(a == null||a.length == 0){
            return 0;
        }
        int result = 0;
        int size = a.length;

        HashMap<T, LinkedList<T>> severalMap = new HashMap<>();

        for (int i = 0; i < size; i++) {
            T t = a[i];
            //以元素本身为键,元素分配到的LinkedList为值
            if(severalMap.get(t) != null){
                severalMap.get(t).add(t);
            }else{
                LinkedList<T> temp = new LinkedList<T>();
                temp.add(t);
                severalMap.put(t, temp);
            }
        }

        //指向长度最大的集合
        LinkedList<T> largestList = null;
        //找到元素最多的集合
        for (LinkedList<T> tempList : severalMap.values()) {
            if(largestList == null){
                largestList = tempList;
                continue;
            }

            if(tempList.size() > largestList.size()){
                largestList = tempList;
            }
            result = largestList.size();
        }   

        return result;

    }

你看,中间那段分配元素就不需要遍历了,直接HsshMap的查询就可以,代码简单速度还更快。

test:

public class Main {
    public static void main(String[] args){
        Integer a[] = {1,1,5,8,6,9,4,7,5,2,6,5,8,5,5,8,6,2};
        String s[] = {"s","s","s","t","t","t","t","t","c"};
        int resultInteger = MostFrequent.getMostFrequentByMap(a);
        int resultString = MostFrequent.getMostFrequentByMap(s);
        System.out.println(resultInteger);
        System.out.println(resultString);

    }

}

结果:
5
5

要注意的是,如果是自己定义的类,要正确重写hashCode和equals方法哦。

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值