左神算法课-找出数组中出现次数超过一半的数及其进阶

原问题描述

给定一个整形数组arr,打印其中出现次数超过一半的数,如果没有这样的数,打印“no such number”;

解法1:

思路:遍历数组中所有的数,用map记录各数出现的次数,key表示原数组中的某个数,value代表出现的次数;找出map中value最大的那个key,再去遍历原数组,看该数是不是满足出现次数大于一半这个条件;
代码:这种情况比较简单就不贴代码了

解法2:

思路:如果存在这样的数,那么按照大小排序过后的数组中间那个数必然是所求的数,按照这个思路,将原数组排序,找出中间那个数,再遍历原数组看是否满足条件(无论如何這一步是省不掉的);
代码:比较简单就不贴了

解法3(左神思路)

思路:如果存在这样的数,那么我每次删掉两个不相同的数,最后剩下的那个就是所求的数,思路比较好理解,但是编码就比较巧妙了,按照这个思路可以有以下编码技巧:所谓删除并不是真正的删除而是记录之后就过去了;temp记录当前等待配对的数,lives表示等待配对的数有几个; 遍历到某个数a[i]时,如果等于等待配对的数,生命值加一,如果不等于,且现在生命值>0,就生命值减1(就相当于同时删除这两个数);如果现在生命值为0,变换等待配对的数为a[i]生命值为1;最终等待配对的数就是剩下的数,拿这个数去验证出现次数是否满足要求;算法复杂度是O(n);
代码:

public static void func2(int[] a) {
            int temp = a[0];
            int lives = 1;
            for (int i = 1; i < a.length; i++) {
                if (a[i] == temp) {
                    lives++;
                } else if (lives > 0) {
                    lives--;
                } else{
                    temp = a[i];
                    lives = 1;
                }   
            }
            int times = 0;
            for (int i = 0; i < a.length; i++) {
                if (temp == a[i])
                    times++;
            }
            if (times > a.length / 2)
                System.out.println(temp);
            else
                System.out.println("no such number");
        }

巧妙处在于如果当前的待配对数的生命值大于零,且来了一个跟配对数不一样的数,就将生命值减一,好像是删除了这两个数;最后那个待配对数就是待验证的数;

进阶题目描述

给定一个整形数组arr长度是N,给定整数k,打印数组中出现次数大于N/k的数,如果没有这样的数,打印“no such number”
思路:首先要知道,出现次数大于k的数最多最多是k-1个,仿照上面的解法3;可以得到:设立一个大小最大为k-1的map,map的key指数组中的某个数,value指该数的生命值。遍历到某数a[i]时,如果map中有a[i]对应的key就将它的value加一,如果map中没有,就看下现在map满没有,如果没有满,就将这个a[i]放进去;如果现在map已经满了,就将所有的map中的value减一,之后将所有的value为0的键值对删除(这样就是变相的删除了不同的k个数);最终将map中所有的值拿去验证出现次数,满足条件的输出;
代码

public static void func3(int[] a, int k) {

        HashMap<Integer, Integer> map = new HashMap<Integer, Integer>(k - 1);
        for (int i = 0; i < a.length; i++) {
            if (!map.containsKey(a[i]))
                if (map.size() < k - 1)
                    map.put(a[i], 1);
                else {
                    Iterator<Integer> iterator = map.keySet().iterator();
                    while (iterator.hasNext()) {
                        int key = iterator.next();
                        int value = map.get(key);
                        if (--value == 0)
                            iterator.remove();
                        else
                            map.put(key, value);
                    }
                }
            else 
                map.put(a[i], map.get(a[i]) + 1);
        }
        boolean flag = false;
        for (Integer key : map.keySet()) {
            for (int i : a)
                System.out.print(i);
            int times = 0;
            for (int i = 0; i < a.length; i++) {
                if (a[i] == key)
                    times++;
            }
            if (times > a.length / k) {
                System.out.println(key);
                flag = true;
            }
        }
        if (!flag)
            System.out.println("no such number");
    }

思路倒是不难想,主要是这种好像删除的操作编码方式,值得借鉴!

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值