真题-求主元素

194 阅读2分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 17 天,点击查看活动详情

Day45 2023/02/20

难度:简单

题目

Frke31dpxO61rDZytb3zM9YG1LCr.png

示例1

输入:arr = {0, 5, 5, 3, 5, 7, 5, 5}
输出:主元素为:5
说明:其中元素5的个数超出总数的一半

示例2

输入: arr = {0, 5, 5, 3, 5, 1, 5, 7}
输出:没有找到主元素
说明:不存在元素的个数超过一半的元素

思路


  • 由题目可知,主元素是数组中出现次数超过一半的元素,若假设让主元素和其他非主元素两两抵消,则数组中如果存在剩余的元素那一定就是主元素,反之,该数组不存在主元素。
    具体步骤:
  1. 选定候选主元素key,初始值为数组第一个元素,计数器count,初始值为0。
  2. 从前往后扫面数组,若如当前元素值等于key,则计数加1,否则减1。
  3. 当计数器值为0的时候,则将该元素设置为新的主元素,并且计数器值也设置为1。
  4. 当扫描完毕,如果计数器的值大于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;
}
  • 时间复杂度 O(n)O(n) --- 需遍历整个数组,其中n为数组的长度
  • 空间复杂度 O(1)O(1) --- 数组为必要空间,除此仅2个常数级变量

总结

  • 本题最简单直接的解法就是遍历数组,并用辅助数组记录每个元素出现的次数,只要存在次数大于数组长度的一半的元素即为主元素,属于空间换时间的方式。