c++面试题(24)-----数组中出现次数超过一半的数字

  • 操作系统:ubuntu22.04
  • IDE:Visual Studio Code
  • 编程语言:C++11

题目描述

数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字。
你可以假设数组非空,并且一定存在满足条件的数字(即一定有一个数字出现次数超过一半)。

示例:

输入: [1, 2, 3, 2, 2, 2, 5, 4, 2]
输出: 2

解法一:摩尔投票法(最优解,时间 O(n),空间 O(1))

这是本题的最佳解法,利用“抵消”思想。
核心思想:

  • 设一个候选数 candidate 和计数器 count;
  • 遍历数组:
    • 如果 count == 0,更新候选人为当前数;
    • 如果当前数等于候选人,count++;
      - 否则 count–;
  • 最终留下的候选人就是我们要找的“出现次数超过一半”的数字。

因为题目保证存在,所以不需要额外验证。

实现代码

#include 

int findMost( std::vector< int > nums )
{
    // 候选人
    int candidate = nums[ 0 ];
    // 投票计数器
    int count = 1;

    for ( int i = 1; i < nums.size(); ++i )
    {
        if ( nums[ i ] == candidate )
        {
            // 相同数字,票数加一
            count++;
        }
        else
        {
            // 不同数字,票数减一
            count--;

            // 票数归零,更换候选人
            if ( count == 0 )
            {
                candidate = nums[ i ];
                count     = 1;
            }
        }
    }

    // 因为题目保证存在,所以直接返回候选人即可
    return candidate;
}

int main()
{
    std::vector< int > nums = { 1, 3, 2, 2, 2, 2, 6 };

    int count = findMost( nums );

    std::cout << count << std::endl;
}

运行结果

2

解法二:哈希表统计(次优解,时间 O(n),空间 O(n))

遍历数组,使用哈希表记录每个数字出现的次数,最后找到出现次数大于 n/2 的那个数字。
示例代码:


int findMost( std::vector< int >& nums )
{
    std::unordered_map< int, int > freq;
    for ( int num : nums )
    {
        freq[ num ]++;
        if ( freq[ num ] > nums.size() / 2 )
            return num;
    }
    return -1;  // 不会执行到这里(题目保证存在)
}

解法三:排序取中位数(时间 O(n log n),空间 O(1) 或 O(n))

将数组排序后,中间位置的元素一定是出现次数超过一半的数字(因为其至少占一半+1)。

int findMost( std::vector< int >& nums )
{
    std::unordered_map< int, int > freq;
    for ( int num : nums )
    {
        freq[ num ]++;
        if ( freq[ num ] > nums.size() / 2 )
            return num;
    }
    return -1;  // 不会执行到这里(题目保证存在)
}

你可能感兴趣的:(c++,c++,算法,数据结构)