牛客之数组中出现次数超过一半的数字

本文介绍了一种算法,用于在数组中找到出现次数超过数组长度一半的数字。通过排序和计数的方式,实现对多数元素的高效查找。如果存在这样的元素,算法将返回该元素,否则返回0。

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

题目描述
数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字。例如输入一个长度为9的数组{1,2,3,2,2,2,5,4,2}。由于数字2在数组中出现了5次,超过数组长度的一半,因此输出2。如果不存在则输出0。

class Solution {
public:
    int MoreThanHalfNum_Solution(vector<int> numbers) {
        int len=numbers.size();
        if(len==0)
            return 0;
        if(len==1)
            return numbers[0];
        for(int i=0;i<len-1;i++)
            if(numbers[i]>numbers[i+1])
                swap(numbers[i],numbers[i+1]);
        int HashLen=numbers[len-1];
        int *Hash = new int[HashLen];//储存数字出现的次数
	    for (int i=0; i < HashLen; i++)
		    Hash[i] = 0;
        for(int i=0;i<len;i++)
        {
            Hash[numbers[i]]++;
            if(Hash[numbers[i]]>(len/2))//次数大于输入数组的一半
                return numbers[i];
        }
        return 0;
    }
};
<think>题目要求:找数组次数超过一半数字(众),如果不存在则按题目要求返回(但代码中未体现不存在的情况,且题目描述不完整) 原代码问题:它遍历数组,每次增加计,并检查当前数字是否超过一半。但是,它会在遍历过程中多次打印同一个数字(如果该数字多次超过一半条件)。而且,如果不存在这样的数字,代码没有返回任何值(函返回类为int,但代码中没有return语句)。 正确做法:使用摩尔投票法(Moore Voting Algorithm)可以在O(n)时间和O(1)空间内解决。或者使用哈希表统计次数,然后检查是否有数字超过一半次数。 这里我将提供两种方法: 方法1:哈希表法 - 遍历数组,用哈希表记录每个数字现的次数。 - 遍历哈希表,找到次数超过数组长度一半数字,返回该数字。 - 如果不存在,则返回0(根据牛客网常见要求,不存在返回0,但具体题目要求可能不同,这里以常见情况处理)。 方法2:摩尔投票法 - 遍历数组,维护一个候选众candidate和它的计count。 - 当count为0时,选择当前数字作为候选。 - 当遇到与候选相同的数字,count加1;否则减1。 - 最后再验证候选众是否真的超过一半(因为摩尔投票法最后得到的候选众不一定满足条件,例如数组没有时)。 由于题目要求函返回int,并且原函名为MoreThanHalfNum_Solution,这里假设题目要求:如果存在超过一半数字则返回该数字,否则返回0(或者根据题目要求,但原题没有,这里按常规处理)。 原代码中只打印不返回,且没有处理不存在的情况,所以我们需要修正。 下面给两种方法的代码: 方法1:哈希表法(简单直接) 方法2:摩尔投票法(更优的空间复杂度) 这里我们首先给哈希表法的完整代码: 方法1:哈希表法 ```cpp #include <unordered_map> #include <vector> #include <iostream> using namespace std; int MoreThanHalfNum_Solution(vector<int>& numbers) { unordered_map<int, int> counts; int len = numbers.size(); for (int num : numbers) { counts[num]++; // 可以在遍历过程中检查,也可以遍历完再检查 } for (auto& pair : counts) { if (pair.second > len / 2) { return pair.first; } } return 0; // 没有找到 } ``` 方法2:摩尔投票法 步骤: 1. 初始化候选人为数组第一个元素,计为1。 2. 从第二个元素开始遍历: 如果当前数字等于候选人,计加1; 否则,计减1; 如果计减到0,则更换候选人为当前数字,并将计重置为1。 3. 最后,检查候选人现的次数是否超过数组长度的一半。 代码: ```cpp int MoreThanHalfNum_Solution(vector<int>& numbers) { int candidate = numbers[0]; // 初始候选人 int count = 1; for (int i = 1; i < numbers.size(); i++) { if (count == 0) { candidate = numbers[i]; count = 1; } else if (candidate == numbers[i]) { count++; } else { count--; } } // 验证候选人的次数是否超过一半 count = 0; for (int num : numbers) { if (num == candidate) count++; } if (count > numbers.size() / 2) { return candidate; } else { return 0; } } ``` 注意:摩尔投票法在第一步遍历中,如果数组没有超过一半,那么最后得到的候选人不一定正确,所以需要第二次遍历验证。 两种方法比较: 哈希表法:时间复杂度O(n),空间复杂度O(n) 摩尔投票法:时间复杂度O(n),空间复杂度O(1) 根据题目要求,如果空间复杂度要求O(1),则使用摩尔投票法。 原题没有说明,但通常要求空间复杂度为O(1),所以摩尔投票法更优。 但是,原代码中使用了哈希表,我们也可以提供哈希表法,但摩尔投票法更优。 下面给完整的摩尔投票法代码(包括边界条件:数组为空的情况): ```cpp int MoreThanHalfNum_Solution(vector<int>& numbers) { if (numbers.empty()) return 0; int candidate = numbers[0]; int count = 1; for (int i = 1; i < numbers.size(); i++) { if (count == 0) { candidate = numbers[i]; count = 1; } else if (candidate == numbers[i]) { count++; } else { count--; } } // 验证 count = 0; for (int num : numbers) { if (num == candidate) count++; } return count > numbers.size() / 2 ? candidate : 0; } ``` 测试用例: 输入:[1,2,3,2,2,2,5,4,2] 输:2 输入:[1,2,3,4,5] 输:0 注意:原题是牛客网上的题目,通常要求不存在时返回0。 因此,我们采用摩尔投票法作为最终答案。 原代码中的问题:没有返回语句,且打印了多次(如果同一个数字多次超过一半,则打印多次)。我们只需要返回一个结果。 所以,我们使用摩尔投票法来重写函。 但是,原函签名是: int MoreThanHalfNum_Solution(vector<int>& numbers) 我们按照上述摩尔投票法实现。 最后,将完整代码(包括必要的头文件)放在一起,但题目中只要求写函,所以这里只给定义。 如果要求完整程序,可以如下: ```cpp #include <vector> using namespace std; class Solution { public: int MoreThanHalfNum_Solution(vector<int> numbers) { if (numbers.empty()) return 0; int candidate = numbers[0]; int count = 1; for (int i = 1; i < numbers.size(); i++) { if (count == 0) { candidate = numbers[i]; count = 1; } else if (candidate == numbers[i]) { count++; } else { count--; } } // 验证 count = 0; for (int num : numbers) { if (num == candidate) count++; } return count > numbers.size() / 2 ? candidate : 0; } }; ``` 注意:这个类是为了符合牛客网的提交格式(通常写在一个Solution类中),如果只需要函,可以去掉类。 相关问题: §§相关问题§§: 1. 如果数组中有两个次数超过一半的元素(但不可能,因为超过一半只能有一个),算法如何处理? 2. 摩尔投票法是否可以用于找数组次数超过n/3的元素?如何实现? 3. 使用哈希表法时,如何优化空间复杂度? 4. 在摩尔投票法中,为什么最后还需要再遍历一次进行验证?</think># 寻找数组次数超过一半数字 您的代码尝试解决"寻找数组次数超过一半数字"问题,但存在几个问题: 1. 没有处理不存在超过一半数字的情况(函缺少返回值) 2. 在遍历过程中打印结果,可能多次打印 3. 没有考虑所有边界情况 ## 完整解决方案 ### 方法1:摩尔投票算法(最优解) 时间复杂度O(n),空间复杂度O(1) ```cpp #include <vector> #include <iostream> using namespace std; int MoreThanHalfNum_Solution(vector<int>& numbers) { if (numbers.empty()) return 0; int candidate = numbers[0]; int count = 1; // 第一遍遍历:找候选众 for (int i = 1; i < numbers.size(); i++) { if (count == 0) { candidate = numbers[i]; count = 1; } else if (candidate == numbers[i]) { count++; } else { count--; } } // 第二遍遍历:验证候选众是否超过一半 count = 0; for (int num : numbers) { if (num == candidate) count++; } return (count > numbers.size() / 2) ? candidate : 0; } int main() { vector<int> test1 = {1, 2, 3, 2, 2, 2, 5, 4, 2}; // 存在超过一半数字 vector<int> test2 = {1, 2, 3, 4, 5}; // 不存在超过一半数字 cout << "Test1 result: " << MoreThanHalfNum_Solution(test1) << endl; // 输2 cout << "Test2 result: " << MoreThanHalfNum_Solution(test2) << endl; // 输0 return 0; } ``` ### 代码解释 1. **初始化候选值**: ```cpp int candidate = numbers[0]; int count = 1; ``` - 从数组第一个元素开始作为候选值 - 计器初始化为1 2. **摩尔投票过程**: ```cpp for (int i = 1; i < numbers.size(); i++) { if (count == 0) { candidate = numbers[i]; count = 1; } else if (candidate == numbers[i]) { count++; } else { count--; } } ``` - 当计器为0时,更换候选值 - 遇到相同元素计器加1,不同元素计器减1 - 算法核心思想:不同元素相互抵消 3. **验证候选值**: ```cpp count = 0; for (int num : numbers) { if (num == candidate) count++; } return (count > numbers.size() / 2) ? candidate : 0; ``` - 重新遍历数组统计候选值次数 - 检查是否真正超过数组长度的一半 ### 方法2:哈希表法 时间复杂度O(n),空间复杂度O(n) ```cpp #include <vector> #include <unordered_map> using namespace std; int MoreThanHalfNum_Solution(vector<int>& numbers) { unordered_map<int, int> countMap; int half = numbers.size() / 2; for (int num : numbers) { countMap[num]++; // 提前返回优化 if (countMap[num] > half) { return num; } } // 没有数字超过一半 return 0; } ``` ### 两种方法对比 | 方法 | 时间复杂度 | 空间复杂度 | 优点 | 缺点 | |------|------------|------------|------|------| | 摩尔投票法 | O(n) | O(1) | 空间效率高 | 需要两次遍历 | | 哈希表法 | O(n) | O(n) | 实现简单 | 空间开销大 | ## 边界情况处理 1. **空数组**: ```cpp if (numbers.empty()) return 0; ``` 2. **数组元素全相同**: ```cpp vector<int> test = {2, 2, 2, 2, 2}; // 正确返回2 ``` 3. **两个数字各占一半**: ```cpp vector<int> test = {1, 2, 1, 2, 1, 2}; // 返回0 ``` 4. **单个元素数组**: ```cpp vector<int> test = {5}; // 正确返回5 ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值