超级水王问题

这篇博客探讨了如何在数组中寻找出现次数超过一半的超级水王数。首先介绍了使用HashMap的暴力解决方法,虽然有效但空间复杂度较高。接着提出了一种空间复杂度为O(1)的算法,通过遍历数组并淘汰不同元素,最终判断剩余元素是否为水王数。该算法利用两个变量跟踪水王数候选者及其生命值,经过两次遍历确定水王数。这种方法巧妙地降低了空间复杂度。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

超级水王数:

描述:
在一个数组中,如果存在一个数,在该数组中出现的次数大于数组长度的一半,那么这个数就是超级水王数

暴力解决:
使用HashMap来存储每个元素出现的次数,最后判断出现次数大于数组长度一半的元素并返回。

代码如下:

 public static void Hash(int[] arr){
        if(arr == null || arr.length == 0){
            System.out.println("数组为空,没有水王数");
        }
        int n = arr.length;
        HashMap<Integer,Integer> map = new HashMap<>();
        for(int i : arr){
            if(map.containsKey(i)){
                map.put(i,(map.get(i) + 1));
            }else{
                map.put(i, 1);
            }
        }
        for(Map.Entry<Integer,Integer> record : map.entrySet()){
            if(record.getValue() > (n >> 1)){
                System.out.println("水王数:" + record.getKey());
            }
        }
    }

但使用HashMap的空间复杂度是O(n)。可不可以得到一个空间复杂度为O(1)的算法呢?

答案是有的。

思路:
从数组第一个元素开始,依次删掉两个不同的数,最后如果有水王数的话,它会剩下来(反过来不成立,也就是剩下来的数不一定是水王数)。
所以我们需要第二次遍历数组,来判断剩下的数的数量超过数组的一半没。

如何实现呢?

将问题转换为以下两步:

1、依次删除数组中两个不同的数
2、 判断是否有数剩余。如果没有数剩余,则不存在水王;如果有数剩余,我们再遍历一次数组,计算该数的真实的出现次数与数组长度的一半进行比较判断是否为水王数

我们需要定义两个变量:变量1:king,来决定当前的水王数候选者。变量2:hp。水王数的生命值,也就是水王数的数量。

如果生命值为0,那么遍历的当前的元素就为水王数。如果生命值不为0,并且当前的元素和水王数候选者并不相同,该元素就会和水王数PK,使HP减一。如果当前的元素和水王数相同,就会增强水王数的实力,使HP+1。

遍历完数组后,如果HP不为0,就再进行一次遍历。统计该水王数候选者在数组中出现的次数,如果总次数大于数组长度的一半,那么就返回该水王数。
否则返回-1.

代码实现:

 //候选者法:
    public static void WaterKing(int[] arr){
        if(arr == null || arr.length == 0){
            System.out.println("数组为空,没有水王数");
        }
        int king = 0; //水王数候选者
        int HP = 0; //代表生命值,每当数组中有相同的数时,生命值加一
        for(int num : arr){  //遍历数组
            if(HP == 0){  //如果生命值为0,候选者为当期的数
                king = num;
                HP = 1;  //生命值为1
            }else if(num != king){  //如果有候选者,且当前值和候选者的值不一样,生命值减一
                HP--;
            }else{  //如果遇到了相同的数,生命值加一
                HP++;
            }
        }
        if(HP == 0){  //如果生命值为0,则表示没有水王数
            System.out.println("没有水王数");
        }
        //再次遍历
        int count = 0;
        int n = arr.length;;
        for(int i : arr){
            if(i == king){
                count++;
            }
        }
        if(count > (n >> 1)){
            System.out.println("水王数为:" + king);
        }else{
            System.out.println("没有水王数");
        }
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

且-听风吟.

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值