开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 17 天,点击查看活动详情
Day45 2023/02/20
难度:简单
题目
示例1
输入:arr = {0, 5, 5, 3, 5, 7, 5, 5}
输出:主元素为:5
说明:其中元素5的个数超出总数的一半
示例2
输入: arr = {0, 5, 5, 3, 5, 1, 5, 7}
输出:没有找到主元素
说明:不存在元素的个数超过一半的元素
思路
- 由题目可知,主元素是数组中出现次数超过一半的元素,若假设让主元素和其他非主元素两两抵消,则数组中如果存在剩余的元素那一定就是主元素,反之,该数组不存在主元素。
具体步骤:
- 选定候选主元素key,初始值为数组第一个元素,计数器count,初始值为0。
- 从前往后扫面数组,若如当前元素值等于key,则计数加1,否则减1。
- 当计数器值为0的时候,则将该元素设置为新的主元素,并且计数器值也设置为1。
- 当扫描完毕,如果计数器的值大于0,则返回当前主元素key,否则返回0。
关键点
- 如何让key始终指向当前主元素,这行代码是关键
else{ key = val; count = 1}, 当count = 0的时候重设当前主元素。
算法实现
c++代码实现-候选主元素的方式
#include <iostream>
#include <vector>
using namespace std;
/**
* @function:查找数组中的主元素
* @param:arr 整型数组
* @return:int 整型
*/
int FindMainElement(vector<int> arr) {
int count = 0, key = arr[0]; // 计数器(初始为0); 当前主元素(初始为数组第一个元素)
for (auto val: arr) { // 遍历数组
if (key == val) count++; // 如果相等的话计数器加1
else {
if (count > 0) count--; // 不等的话,若计数大于0,计数减1
else { // 不等的话,若计数器等于0,将计数器设置为1,并将该元素设置为主元素
key = val;
count = 1;
}
}
}
return count > 0 ? key : 0; // 如果计数器指大于0,则返回当前主元素key,否则没有主元素返回0
}
int main () {
//测试一下(两组数据)
vector<int> arr = {0, 5, 5, 3, 5, 7, 5, 5}; // 数据1
// vector<int> arr = {0, 5, 5, 3, 5, 1, 5, 7}; // 数据2
int key = FindMainElement(arr); //调用
if(key) cout << "主元素为:" << key;
else cout << "没有找到主元素!!!";
return 0;
}
- 时间复杂度 --- 需遍历整个数组,其中n为数组的长度
- 空间复杂度 --- 数组为必要空间,除此仅2个常数级变量
总结
- 本题最简单直接的解法就是遍历数组,并用辅助数组记录每个元素出现的次数,只要存在次数大于数组长度的一半的元素即为主元素,属于空间换时间的方式。