在数组中找到出现次数大于N/K的数

原始题目:给定一个整形数组arr,打印出其中出现次数大于一半的数,如果没有这样的数,打印提示信息。

进阶题目:给定一个整形数组arr,再给定一个整数k,打印所有出现次数大于N/K的数,如果没有这样的数,打印提示信息。

要求:原始问题要求时间复杂度为O(N),额外空间复杂度为O(1)。进阶问题要求时间复杂度为O(N*K),额外空间复杂度为O(K)。

原始问题:设定一个候选值cands,以及记录次数的变量times,当前值如果等于候选值时times加一,否则times减一,即将两个不同的值同时消除,这样的话最终剩下的值即为大于一半的数,但是也应该进行最后的校验,因为剩下的值不一定是大于一半的数,但是大于一半的数一定会被剩下。具体代码实现如下所示:

public class PrintHalfMajor {
    public void printHalfMajor(int[] arr){
        int cand=0;
        int times=0;
        for (int i=0;i!=arr.length;i++){
            if (times==0){
                cand=arr[i];
                times=1;
            }else if (arr[i]==cand){
                times++;
            }else{
                times--;
            }
        }
        times=0;
        for (int i=0;i!=arr.length;i++){
            if (arr[i]==cand){
                times++;
            }
        }
        if (times>arr.length/2){
            System.out.println(cand);
        }else{
            System.out.println("没有这种数!");
        }
    }

    public static void main(String[] args) {
        int[] arr=new int[]{1,5,2,2,2};
        PrintHalfMajor printHalfMajor=new PrintHalfMajor();
        printHalfMajor.printHalfMajor(arr);
    }
}

进阶题目:可以采用原始题目的思路,因为找到大于一半的数时选择的是一个候选值,因此可以想到在找大于N/K的数时,应该设置k-1个候选值,然后同样比较候选值与当前值是否相等,若相等则对应的次数加一,否则减一,当然要判断候选值是否为k-1,若没有达,则直接将当前值作为候选值,如果到达k-1了,且当前值不等于候选值中的数值,此时应该将候选值中的数的次数都减一,这样便能找到要求的数值。具体代码实现如下所示:

import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

public class PrintHalfMajor2 {
    public void printHalfMajor2(int[] arr,int k){
        if (k<2){
            System.out.println("不合规矩!");
            return ;
        }
        HashMap<Integer,Integer> cands=new HashMap<>();
        for (int i=0;i!=arr.length;i++){
            if (cands.containsKey(arr[i])){
                cands.put(arr[i],cands.get(arr[i])+1);
            }else{
                if (cands.size()==k-1){
                    allCandsMinusone(cands);
                }else{
                    cands.put(arr[i],1);
                }
            }
        }
        HashMap<Integer,Integer> reals=getReals(arr,cands);
        boolean hasPrint=false;
        for (Map.Entry<Integer,Integer> set:cands.entrySet()){
            Integer key=set.getKey();
            if (reals.get(key)>arr.length/k){
                hasPrint=true;
                System.out.println(key+" ");
            }
        }
        System.out.println(hasPrint?" ":"无该数值!");
    }
    /*当候选值达到k-1时更新候选值的次数*/
    private void allCandsMinusone(HashMap<Integer,Integer> map) {
        List<Integer> removeList=new LinkedList<>();
        for (Map.Entry<Integer,Integer> set:map.entrySet()){
            Integer key=set.getKey();
            Integer value=set.getValue();
            if (value==1){
                removeList.add(key);
            }
            map.put(key,value-1);
        }
        for (Integer removeKey:removeList){
            map.remove(removeKey);
        }
    }
    /*获取候选值在原数组中出现的总次数*/
    private HashMap<Integer,Integer> getReals(int[] arr, HashMap<Integer,Integer> cands) {
        HashMap<Integer,Integer> reals=new HashMap<>();
        for (int i=0;i!=arr.length;i++){
            int curNum=arr[i];
            if (cands.containsKey(curNum)){
                if (reals.containsKey(curNum)){
                    reals.put(curNum,reals.get(curNum)+1);
                }else{
                    reals.put(curNum,1);
                }
            }
        }
        return reals;
    }

    public static void main(String[] args) {
        int[] arr=new int[]{1,5,2,2,2,1,1};
        PrintHalfMajor2 printHalfMajor2=new PrintHalfMajor2();
        printHalfMajor2.printHalfMajor2(arr,3);
    }

}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值