`
frank-liu
  • 浏览: 1683812 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

求数组中Majority元素的方法

阅读更多

问题描述

在一个规模为N的数组A中,所谓的Majority元素就是指出现次数大于N/2的元素(因而最多只有一个这种元素)。比如数组

3, 3, 4, 2, 4, 4, 2, 4, 4 中间有Majority元素4。而数组3, 3, 4, 2, 4, 4, 2, 4则没有majority元素。需要一个算法,如果majority元素存在的话,就找出来,如果不存在,则给出报告。

 

下意识解法

通过这个问题,我们可以很快得出一个如下的方法。就是首先定义一个HashMap,里面存放数组里面的每个元素以及出现的次数。可以通过两个过程来做。

        第一步是映射,将每个元素放进去,如果HashMap里面已经有元素了,则该元素对应的出现次数加一,否则新增加该元素,出现的次数设置为1.

        第二步就是遍历整个HashMap,判断是否找到出现次数大于数组长度一半的。如果有,则返回该元素以及出现的次数。否则显示没有该元素。

 

详细的代码如下:

 

 

import java.util.HashMap;
import java.util.Map;

public class MaxFind
{
    private int maxValue;
    private int occurence;
    private int[] array;
    private HashMap<Integer, Integer> map = new HashMap<Integer, Integer>();

    public MaxFind(int[] array)
    {
        this.array = array;
    }

    public void map()
    {
        if(array == null || array.length == 0)
            return;
        for(int i = 0; i < array.length; i++)
        {
            if(map.containsKey(array[i]))
            {
                int key = array[i];
                map.put(key, map.get(key) + 1);
            }
            else
                map.put(array[i], 1);
        }
    }

    public int find()
    {
        this.occurence = 0;
        getValueAndOccurence();
        if(this.occurence > array.length / 2)
            return this.maxValue;
        else
            return -1;
    }

    private void getValueAndOccurence()
    {
        for(Map.Entry<Integer, Integer> entry : map.entrySet())
        {
            if(entry.getValue() > this.occurence)
            {
                this.occurence = entry.getValue();
                this.maxValue = entry.getKey();
            }
        }
    }

    public static void main(String[] args)
    {
        int[] array0 = {3, 3, 4, 2, 4, 4, 2, 4, 4};
        int[] array1 = {1, 2, 3, 4, 5, 6, 7, 8, 9};
        MaxFind finder = new MaxFind(array0);
        finder.map();
        if(finder.find() > 0)
            System.out.println(finder.find());
    }
}

 

分析

        整体的代码实现采用一种相对OO一点的方式,因为两个方法都需要访问同一个数组和HashMap,可以将数组和HashMap作为类的成员。另外,HashMap的泛型参数必须为Integer,后面比较的时候会自动的装箱和拆箱。

        这个方法的时间复杂度为O(N),因为要用到一个额外的HashMap,所以存储的空间复杂度也是O(N).

        总的来说,这个方法很简单,没多少好说的。

 

进一步的要求

        现在,我们看看是否还有进一步可以改进的地方。如果要求空间复杂度为O(1)呢?是否有方法?

分析

        这个问题更苛刻的一点在于原来的办法可以用一个HashMap来存放统计结果。现在只能允许用O(1)的空间意味着只能用一个普通的数值变量来帮助解决问题。

        这个时候就需要根据问题本身来进一步考虑一下。我们可以看到,如果存在一个majority元素的话,那么肯定一半多的元素都是这一个。我们考虑一种抵消的策略。如果该元素去和所有其他的元素比较,如果不同的都抵消的话,那么剩下的这个元素肯定就是majority元素。那么,具体的抵消步骤该怎么走呢?何况一开始我们也不知道哪个元素是majority元素。

进一步分析

        假设我们一开始从数组的开头,碰到某个元素的时候,就设置该元素为当前元素。当前出现的次数为1.后面,如果接着碰到的元素和该元素相同,则当前次数加1,否则减1.如果当前出现的次数为0,则表示当前元素不确定。如果结合我们有majority元素这个前提的话,必然最后的结果是大于0的,而且最终获取到的值就是majority元素。

        但是,这种分析还存在一个问题。我们考虑的是majority元素存在的情况。如果majority元素不存在,也有可能出现最终元素出现次数大于0的情况。比如说如下的序列: 1, 1, 1, 2, 2, 2, 3。 这个序列没有majority元素,但是可以按照前面方法得到出现次数大于0的数字3.

      很显然,数组中存在majority元素必然可以推出按照我们的方法得到的结果。但是按照我们的方法得到的结果却不能推出数组中存在majority元素。我们的方法只是判断的必要条件。

        既然该方法不够充分,我们就还需要进一步的验证。接下来的步骤可以非常简单。我们再一次遍历这个数组,只要找按照前面我们的方法推出来的这个majority元素的次数,如果结果确实> N/2,则这个元素就是我们找到的。否则就没有找到。

        至此,我们整个过程就整理出来了。概括一下的话可以分为两个步骤:

1. parse阶段

       通过一个抵消的过程遍历数组,得到一个最终出现次数不为0的元素。如果出现的元素为0,则表明没有majority元素。

2. find阶段

        按照前面找到的元素,到数组里面核对一下。

 

具体实现的代码如下:

 

public class Majority
{
    private static int count;
    private static int currentValue;

    public static void parse(int[] array)
    {
        if(array == null || array.length == 0)
            return;
        count = 1;
        currentValue = array[0];
        for(int i = 1; i < array.length; i++)
        {
            if(array[i] == currentValue)
                count++;
            else
                count--;
            if(count == 0)
                currentValue = array[i];
        }
    }

    public static boolean find(int[] array)
    {
        if(count == 0)
            return false;
        count = 0;
        for(int i = 0; i < array.length; i++)
        {
            if(array[i] == currentValue)
                count++;
        }
        if(count > array.length / 2)
            return true;
        else 
            return false;
    }

    public static void main(String[] args)
    {
        int[] array1 = {1, 2, 3, 4, 5};
        int[] array2 = {1, 2, 2};
        int[] array3 = {1, 2, 2, 2, 3, 4};

        // for array1 case 1
        parse(array1);
        if(find(array1))
            System.out.println("value:" + currentValue + "\tcount:" + count);
        else
            System.out.println("No majority value found.");

        // case 2
        parse(array2);
        if(find(array2))
            System.out.println("value:" + currentValue + "\tcount:" + count);
        else
            System.out.println("No majority value found.");


        // case 3
        parse(array3);
        if(find(array3))
            System.out.println("value:" + currentValue + "\tcount:" + count);
        else
            System.out.println("No majority value found.");
    }
}

 

该算法需要遍历数组两次,总的时间复杂度为O(N) ,空间复杂度为O(1)。

总结

        寻找majority元素的方法还有其他的。比如说,先将元素排序,然后再进行判断。因为如果有majority元素的话,取数组中间点的那个元素即为所要找的那个。不过这种方法首先排序就需要O(NlogN)的时间复杂度,并不是很理想。

        至于我们那个分两次遍历数组的方法,关键在于利用majority元素的特性进行抵消。

 

参考资料

A linear time majority vote algorithm

 

 

 

分享到:
评论

相关推荐

    php数组的一些常见操作汇总

    下面将详细介绍数组操作的几个方面,包括数组求和、求数组的最大值和最小值、求数组的最大值和次大值以及找出数组中出现次数超过一半的元素。 首先,我们来看数组求和。在数组中求和的问题,虽然简单,但是通过递归...

    寻找一堆数字中的主元素

    在计算机科学和数据分析领域,"主元素"(Majority Element)是一个重要的概念,尤其是在数据处理和算法设计中。主元素是指在给定的一组数字中出现次数超过数组长度一半的元素。如果存在这样的元素,那么它就是数组的...

    php实现数组中出现次数超过一半的数字的统计方法

    在PHP中统计数组中出现次数超过一半的数字,这实际上是算法题目中的一个常见问题,被称作“摩尔投票法”(Boyer-Moore Majority Vote Algorithm)的一个应用。这种问题的难点在于,如何在一次遍历数组的情况下找出这个...

     算法设计大作业之寻找多数元素.doc

    例如,在一个序列中,`candidate` 函数会逐个检查元素,通过递归找到可能的多数元素,然后 `majority` 函数验证其是否满足多数元素条件。 总结: 寻找多数元素的算法是一种高效的方法,利用了多数元素的性质来减少...

    剑指Offer(Python多种思路实现):数组中出现次数超过一半的数字

    这种方法基于一个观察:如果有这样一个多数元素,每次从数组中选择两个不同的元素并消除它们,最后剩下的那个元素就是多数元素。在Python中,我们可以用以下方式实现: ```python class Solution: def ...

    python入门-leetcode面试题解之第229题多数元素II.zip

    在这个例子中,`Counter(nums)`计算了数组中每个元素的频率,`majority_count`定义了多数元素的阈值,然后通过列表推导式找出所有计数超过这个阈值的元素。 对于求职面试来说,熟练掌握这类问题的解法是非常重要的...

    寻找多数元素的C++程序

    在编程领域,寻找多数元素(Majority Element)是一项常见的任务,尤其在算法设计和数据处理中。多数元素指的是在一个整数数组中出现次数超过数组长度一半的元素。本主题将详细探讨如何用C++语言来解决这个问题。 ...

    算法题总结 2741

    13. **数组中出现次数超过一半的数字**:摩尔投票法(Majority Voting Algorithm)是解决这类问题的经典方法。 14. **数组中最小的 k 个数**:可以使用快速选择算法或者优先队列(堆)来寻找最小的k个数。 15. **...

    wujie199#CS#39. 数组中出现次数超过一半的数字1

    如果前面查找了 i 个元素,且 cnt == 0,说明前 i 个元素没有 majority,或者有 majority,但是出现的次数少于 i / 2 ,因为如果

    基于Java代码实现数字在数组中出现次数超过一半

    一种常见的方法是先对数组进行排序,然后找到位于中间位置的元素,因为数组长度是奇数,中间的元素出现次数会超过一半。但是,这种方法的时间复杂度至少为O(NlogN),考虑到快速排序的平均情况。 方法二:使用散列表...

    数据结构与算法题解

    - 求出数组中除了当前元素外所有其他元素的乘积。 - **PartitionArray** - 分割数组,使得左右两边的元素满足一定条件。 - **FirstMissingPositive** - 寻找数组中缺失的第一个正整数。 - **2Sum** - 寻找数组中...

    Coding Interview in Java

    10. 深入理解堆和优先队列:在问题如Kth Largest Element in an Array(数组中第K大的元素)中会用到堆和优先队列的知识。 11. 栈与单调栈问题:例如Valid Parentheses(有效的括号)、Largest Rectangle in ...

    lintcode题解

    - **MajorityNumber(多数元素)**:找出数组中出现次数超过一半的元素。 ### 堆和堆栈操作 - **Heapify(堆化)**:构建或重构一个堆,使其满足堆的特性。 - **LRUCache(最近最少使用缓存)**:利用哈希表和双端...

    第2周-2A-减而治之1

    - 众数是数组中出现次数超过数组长度一半的元素。寻找众数可以通过减治法实现,如摩尔投票算法,每次比较两个不同的元素并消除它们,如果某元素剩余数量达到n/2,那么它就是众数。如果没有众数,该算法也会返回正确...

    有赞2019校招前端笔试.docx

    第十三个问题讨论了数组的 leader 元素,要求计算查找数组中所有 leader 元素的最优算法时间复杂度。这个问题可以使用算法的基本性质解决,查找数组中所有 leader 元素的最优算法时间复杂度是 O(n)。 第十四个问题...

    剑指offer编程题66道题目描述及java代码实现汇总

    1. **数组中出现次数超过一半的数字**:这是一道常见的计数问题,可以使用摩尔投票法(Majority Vote Algorithm)解决,避免使用排序或哈希表。 2. **二维数组中的查找**:在给定的二维矩阵中寻找特定元素,可以...

    zhongshu.zip_visual c_众数问题

    最后,通过比较左右两部分的众数在完整数组中的出现次数来确定整个数组的众数。 然而,这种递归方法在处理大规模数据时效率不高,因为它涉及到多次的数组遍历和分割。对于众数问题,更常见且高效的算法是Boyer-...

    MajoritySearch.rar_数据结构_C/C++_

    在本资源"MajoritySearch.rar"中,包含的是一个C语言实现的数据结构和算法的应用,主要目的是寻找数组中的“多数元素”(Majority Element)。多数元素是指在一个整数数组中出现次数超过数组长度一半的元素。这个...

    算法面试通关40讲完整课件 22-24 分治、递归、回溯

    - **找多数元素 (Majority Element)**:在数组中找出出现次数超过数组长度一半的元素。 - **最大子数组和 (Maximum Subarray)**:求解数组中连续子数组的最大和。 - **判断字符串是否为Anagram**:检查两个字符串...

    基于C语言解决众数问题(源码)

    findMajority 函数用于寻找数组中的众数,利用了 Boyer-Moore Majority Vote 算法。 算法的核心思想是遍历数组,通过计数器来记录当前的众数和出现次数。 如果当前元素与众数相同,则计数器加一;否则计数器减一。当...

Global site tag (gtag.js) - Google Analytics