169. Majority Element(遗留问题)

一、题意
Given an array of size n, find the majority element. The majority element is the element that appears more than ⌊ n/2 ⌋ times.

You may assume that the array is non-empty and the majority element always exist in the array.
二、分析和解答
1、返回出现次数超过 ⌊ n/2 ⌋ 次的数。我的想法:使用HashMap保存每一个数以及该数出现的次数,找到次数最多的那位即可(其实都出现总数的一半了,那肯定是最多的了)。代码如下:

    public int majorityElement(int[] nums) {
        int max = 0;
        int result = -1;
        HashMap<Integer,Integer> map = new HashMap();
        for(int i=0;i<nums.length;i++){
            if(map.containsKey(nums[i]))
                map.put(nums[i],map.get(nums[i]) + 1);
            else//这里的else容易忘记,导致错误!
                map.put(nums[i],1);
        }

        Set<Integer> set = map.keySet();
        for(Integer key : set){
            int value = map.get(key);
            if(max < value){
                max = value;
                result = key;
            }
        }
        return result;
    }

这里回顾一下HashMap的遍历方法:
(1)得到key的集合,然后根据key从map中得到value,如上面的代码(通过键来获取值);
(2)通过map.values()来获取所有的值的集合,然后进行遍历输出;由于这样无法的到key,还得单独获取,所以在这里不适用;
(3)通过获取键值对的方式,map.entrySet()

 Set<Map.Entry<Integer,Integer>> set = map.entrySet();
        for(Map.Entry<Integer,Integer> entry : set){
            int key = entry.getKey();
            int value = entry.getValue();
            if(max < value){
                max = value;
                result = key;
            }
        }

(4)通过entrySet的遍历器

        Set<Map.Entry<Integer,Integer>> set = map.entrySet();
        Iterator<Map.Entry<Integer,Integer>> it = set.iterator();
        while(it.hasNext()){
            Map.Entry<Integer,Integer> entry = it.next();
            int key = entry.getKey();
            int value = entry.getValue();
            if(max < value){
                max = value;
                result = key;
            }
        }

2、还可以使用排序。在这里可以复习一下java相关的排序函数
3、还可以使用分治法和位操作来完成。其实这个分治法就是快速排序划分的变形,我开始也想到使用划分操作来获得中间值,但是没想通。
参考《剑指offer》可以知道:成熟的O(n)的算法可以得到数组中任意第k大的数字。
其实我们要得到的就是数组的中间位置的值,而随机快排的划分算法返回的值就是选择pivot那个值在数组中的位置,随机快排的pivot的值的选择是随机的。于是,当随机选中的那个数字所对应的下标正好是n/2,那么就是所求的中位数;若对应的下标小于n/2,那么中位数就应该在它的右边;若对应的下标大于n/2,那么中位数就应该在它的左边。
我写的代码如下(超时了过去了一半的案例):

int paratition(int[] nums,int low,int high){
        Random r = new Random();
        int index = r.nextInt(high - low + 1) + low;
        int pivot = nums[index];
        int t = nums[low];
        nums[low] = nums[index];
        nums[index] = t; 
        while(low < high){
            //while(high < nums.length && nums[high] < pivot)
            while(low < high && nums[high] >= pivot)
                high--;        
            nums[low] = nums[high];
            //while(low < nums.length && nums[low] > pivot)
            while(low < high && nums[low] <= pivot)
                low++;
            nums[high] = nums[low];

            //int t = nums[low];
            //nums[low] = nums[high];
            //nums[high] = t;                                                

        }
        nums[low] = pivot;
        return low;  
    }
    public int majorityElement(int[] nums) {
        int low = 0,high = nums.length -1;
        int middle = (low + high) / 2;
        int key = paratition(nums,low,high);

        while(key != middle){
            if(key < middle)
                key = paratition(nums,key+1,high);
            else
                key = paratition(nums,low,key-1);
        }
        if(key == middle)
            return nums[middle];
        return nums[middle];
    }

没找到有人有这么个写法,时间复杂度(快排的)我还不会分析,这是一个遗留问题!
4、这种方法是基于如果一个数在这个数组中是出现次数最多的,那么在删去一对不同的数后剩下的子数组中,该数也是出现次数最多的。这种算法名为Moore Voting Algorithm。代码为:

    public int majorityElement(int[] nums) {
        int majority = -1;
        int count = 0;
        for(int i=0;i<nums.length;i++){
            if(count == 0){
                majority = nums[i];
            }
            if(majority == nums[i])
                count++;
            else
                count--;
        }
        if(count > 0)// 更详细: >= nums.length/2+1
            return majority;
        return majority;
    }

我们遍历这个数组的时候,定义一个count用来计数,这个超过一半的数,它遇到自己就给count加1,遇到不是自己的数,就给count减1,最后会怎样呢,count肯定大于0呐,因为这个数的个数超过一半。好,进一步的,我们先随便找个数当这个老大(个数超过一半),如果它的个数不超过一半,就会在相消中时count为0,那么就把它换掉,最后剩下的那个就是,个数超过一半的那个数了。【这段话是复制的】
初始选第一个元素,依次比对它和其它的元素,若相等则其票数加一,反之则减一,当其票数为0时,更换投票对象为当前的元素,继续执行,最终即可得结果(前提的数组中存在这样的数,否则结果不确定是什么,依赖于元素的摆放顺序)。

参考:http://blog.csdn.net/zdavb/article/details/47837017
https://www.cnblogs.com/tjuloading/p/4614397.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值