majority element(数组中找出出现次数最多的元素)

本文介绍三种寻找数组中出现次数超过n/2的多数元素的方法:排序法、HashMap法及多数投票算法。多数投票算法时间复杂度为O(n),空间复杂度为O(1),仅需两次遍历即可找到多数元素。

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.

这里题目要求找出出现次数超过n/2的元素。

可以先排序,出现次数超过一半的元素会出现在数组中间。时间O(nlogn)空间O(1)

无论找出出现次数多于多少的元素,都可以使用HashMap来找,在往map中添加的时候就可以判断了。O(n)时间复杂度和空间复杂度

 public int majorityElement(int[] nums) {
        if(nums.length==1) return nums[0];
        HashMap<Integer,Integer> map=new HashMap<>();
        for(int i=0;i<nums.length;i++){
            if(map.get(nums[i])==null)
                map.put(nums[i],1);
            else{
                int num=map.get(nums[i]);
                if(num+1>nums.length/2) return nums[i];
                map.put(nums[i],num+1);
            }
        }
        return 0;
    }

多数投票算法。。

该算法时间复杂度为O(n),空间复杂度为O(1),只需要对原数组进行两趟扫描,并且简单易实现。第一趟扫描我们得到一个候选节点candidate,第二趟扫描我们判断candidate出现的次数是否大于⌊ n/2 ⌋。这里题目说元素必然存在,所以第二趟就省略了。先看代码.

   public int majorityElement(int[] nums) {
        int candidate=0;int count=0;
        for(int i=0;i<nums.length;i++){
            if(count==0){
                count++;
                candidate=nums[i];
            }else if(candidate==nums[i]) count++;
            else count--;
        }
        return candidate;
    }

我们来看看原理。(参考http://blog.youkuaiyun.com/kimixuchen/article/details/52787307)

因为存在超过一半次数的元素,上面算法中,该元素会去抵消其他的元素(抵消一个count就变为0)。然后该元素还有剩余,所以最后的candidate就是该元素了。

为了解析算法的原理,我们只要考虑存在多数元素的情况即可,因为第二趟扫描可以检测出不存在多数元素的情况。

举个例子,我们的输入数组为[1,1,0,0,0,1,0],那么0就是多数元素。 
首先,candidate被设置为第一个元素1,count也变成1,由于1不是多数元素,所以当扫描到数组某个位置时,count一定会减为0。在我们的例子中,当扫描到第四个位置时,count变成0.

count 值变化过程: 
[1,2,1,0……

当count变成0时,对于每一个出现的1,我们都用一个0与其进行抵消所以我们消耗掉了与其一样多的0,而0是多数元素,这意味着当扫描到第四个位置时,我们已经最大程度的消耗掉了多数元素。然而,对于数组从第五个位置开始的剩余部分,0依然是其中的多数元素(注意,多数元素出现次数大于⌊ n/2 ⌋,而我们扫描过的部分中多数元素只占一般,那剩余部分中多数元素必然还是那个数字)。如果之前用于抵消的元素中存在非多数元素,那么数组剩余部分包含的多数元素就更多了。

类似的,假设第一个数字就是多数元素,那么当count减为0时,我们消耗掉了与多数元素一样多的非多数元素,那么同样道理,数组剩余部分中的多数元素数值不变。

这两种情况证明了关键的一点:数组中从candidate被赋值到count减到0的那一段可以被去除,余下部分的多数元素依然是原数组的多数元素。我们可以不断重复这个过程,直到扫描到数组尾部,那么count必然会大于0,而且这个count对应的candinate就是原数组的多数元素。

 

对于其他求不是超过n/2的,而是n/k的,可以使用map。

转载于:https://www.cnblogs.com/xiaolovewei/p/8085969.html

<think>好的,用户想找到数组中出现次数超过一半的元素,这个问题看起来是常见的算法题。根据提供的引用资料,有几种方法可以解决这个问题。我需要先理清楚每种方法的思路,然后比较它们的优缺点,再给出具体的实现步骤。 首先,用户提到的引用[2]中提到可以先排序,然后返回中间的元素。因为如果有一个元素超过一半,排序后中间的位置必然是该元素。这种方法的时间复杂度主要取决于排序算法,比如快速排序是O(n log n),空间复杂度如果是原地排序的话是O(1)。不过当数组很大时,排序可能不是最优解,但实现起来简单。 然后引用[3]、[5]提到的摩尔投票法,这种方法可以在O(n)时间和O(1)空间内完成。摩尔投票法的核心是抵消不同的元素,剩下的候选者就是目标。具体步骤是遍历数组,记录当前候选元素和出现次数,遇到相同元素加1,不同则减1,当次数为0时更换候选元素。这个方法效率高,适合处理大数据量的情况,但需要理解其原理,可能对初学者来说有点抽象。 另外,引用[4]提到用哈希表统计次数,这种方法直观,遍历数组记录每个元素的出现次数,最后找出次数超过一半的元素。时间复杂度是O(n),但空间复杂度也是O(n),因为需要存储哈希表。当元素范围较大时,哈希表可能会占用较多内存,但在实际应用中可能更容易理解和实现。 用户可能希望得到不同方法的比较,以及具体的实现代码。需要根据不同的场景选择合适的方法。例如,如果空间有限,摩尔投票法更好;如果更注重代码可读性,哈希表方法可能更合适。而排序方法虽然简单,但时间复杂度较高,可能不适合处理大规模数据。 现在需要考虑如何将这些方法清晰地呈现给用户,包括步骤、代码示例以及各自的优缺点。同时,根据用户提供的引用,需要正确引用对应的资料,比如引用[2]对应排序法,引用[3]、[5]对应摩尔投票法,引用[4]对应哈希表法。 需要确保代码部分正确,例如Python中的摩尔投票法实现是否准确,哈希表的使用是否正确统计次数。同时,对于排序方法,需要注意如果数组中没有超过一半的元素时的情况,但根据问题描述,题目保证存在这样的元素,所以不需要额外处理。 最后,生成相关问题时要围绕这个主题,比如不同方法的比较、时间空间复杂度、优化方法等。用户可能还想知道如何处理不存在多数元素的情况,但题目假设总是存在,所以可能不需要涵盖,但可以作为扩展问题。</think>### 查找数组中出现次数超过一半的元素 #### 方法一:排序法(时间复杂度 $O(n \log n)$) 1. **原理**:若某个元素出现次数超过数组长度的一半,排序后数组中间位置必定是该元素[^2] 2. **实现步骤**: - 对数组进行排序 - 直接返回数组中间位置的元素 ```python def majority_element_sort(nums): nums.sort() return nums[len(nums)//2] ``` #### 方法二:摩尔投票法(时间复杂度 $O(n)$) 1. **原理**:通过元素抵消策略找到候选元素,最终剩余元素即为目标[^3][^5] 2. **实现步骤**: - 初始化候选元素 `candidate` 和计数器 `count` - 遍历数组: - 当计数器为0时,更新候选元素 - 遇到相同元素计数器+1,不同则-1 ```python def majority_element_moore(nums): candidate = None count = 0 for num in nums: if count == 0: candidate = num count += 1 if num == candidate else -1 return candidate ``` #### 方法三:哈希统计法(时间复杂度 $O(n)$) 1. **原理**:使用哈希表记录元素出现次数,找到超过半数的元素[^4] 2. **实现步骤**: - 创建哈希表统计元素频率 - 遍历哈希表找到频率超过半数的元素 ```python def majority_element_hash(nums): counts = {} for num in nums: counts[num] = counts.get(num, 0) + 1 if counts[num] > len(nums)//2: return num return -1 # 根据题目保证不会执行到这里 ``` #### 方法比较 | 方法 | 时间复杂度 | 空间复杂度 | 适用场景 | |------------|------------|------------|----------------------| | 排序法 | $O(n \log n)$ | $O(1)$ | 快速实现的小规模数据 | | 摩尔投票法 | $O(n)$ | $O(1)$ | 大规模数据最优解 | | 哈希统计法 | $O(n)$ | $O(n)$ | 需要频率统计的场景 |
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值