多数元素(超级水王问题扩展)

给定一个长度为N的数组arr,和一个大于1的正整数K,如果有哪些数出现的次数大于N/K,就返回这些数
要求:时间复杂度O(N) 额外空间复杂度O(K)

多数元素-超级水王问题,这个是比较基础的

思考:最多会有k-1个数
具体问题思考:当 k = 4时 哪些数出现的次数 大于 N / 4;
有哪些性质呢?
性质1:
次数大于 N/4的次数最多是3个,反证法:如果多余三个,那么就会出现,总数大于 N,所以假设不存在;

抵消阶段:
1.每次抵消k个不同的的数;如果数组中存在大于 N/K的数,那么一定会被保留下来,
保留下来的不一定是数,次数不一定大于N/K的数;
计数阶段:
1.对于每一个候选结果进行重新计数,判断每个结果是否满足要求;

代码:

private List<Integer> getSuperWaterExtension(int[] arr, int K) {
        int N = arr.length;
        int M = N / K;
        //候选表,最大列表为K-1
        Map<Integer, Integer> candis = new HashMap<>();

        for (int value : arr) {
            if (candis.containsKey(value)) {
                candis.put(value, candis.get(value) + 1);
            } else {
                if (candis.size() == K - 1) {
                    allCandisMinusOne(candis);
                } else {
                    candis.put(value, 1);
                }
            }
        }
        Map<Integer, Integer> reals = getReals(arr, candis);

        List<Integer> res = new ArrayList<>();

        reals.forEach((key,value) -> {
            if(value > M) {
                res.add(key);
            }
        });

        return res;
    }

    /**
     * 对候选的数据进行计数
     */
    private Map<Integer,Integer> getReals(int[] arr,Map<Integer,Integer> candis){
        Map<Integer,Integer> res = new HashMap<>();
        for(int num : arr){
            if(!candis.containsKey(num)) continue;

            res.put(num,res.getOrDefault(num,0) + 1);
        }
        return res;
    }


    //所有的候选数减去一
    private void allCandisMinusOne(Map<Integer, Integer> candis) {
        List<Integer> removes = new ArrayList<>();
        for (Integer key : candis.keySet()) {
            if (candis.get(key) == 1) {
                removes.add(key);
            } else {
                candis.put(key, candis.get(key) - 1);
            }
        }
        // 删除无效的候选
        for (Integer num : removes) {
            candis.remove(num);
        }
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值