字节青训Marscode——8:找出整形数组中超过一半的数

news2024/12/27 10:09:54

问题描述

小R从班级中抽取了一些同学,每位同学都会给出一个数字。已知在这些数字中,某个数字的出现次数超过了数字总数的一半。现在需要你帮助小R找到这个数字。


测试样例

样例1:

输入:array = [1, 3, 8, 2, 3, 1, 3, 3, 3]
输出:3

样例2:

输入:array = [5, 5, 5, 1, 2, 5, 5]
输出:5

样例3:

输入:array = [9, 9, 9, 9, 8, 9, 8, 8]
输出:9

步骤1:问题定义与分析

题目要求:

从一个整数数组 array 中找出某个出现次数超过数组长度一半的数字,保证这样的数字一定存在。

输入与输出:
  • 输入:一个整数数组 array,长度为 n
  • 输出:数组中某个出现次数超过 n / 2 的数字。
限制与边界条件:
  1. 数组中保证一定存在满足条件的数字。
  2. 数组长度 n 的范围未明确给出,但假设为合理范围(如 1 <= n <= 10^6)。
  3. 只需要输出符合条件的任意一个数字,不需要处理无解的情况。
问题性质:
  • 根据题意,某个数字的出现次数超过总数的一半,称为 多数元素
  • 这种问题可以通过经典的算法(如摩尔投票法)高效解决,而不需要使用暴力计数法。

步骤2:算法设计与分析

方法1:哈希表计数
  • 使用哈希表统计每个数字的出现次数。
  • 遍历数组,当某个数字的出现次数超过 n / 2 时返回该数字。
时间复杂度与空间复杂度:
  • 时间复杂度:O(n),需要遍历数组。
  • 空间复杂度:O(n),存储哈希表。
适用场景

适用于小规模数据,且有足够的内存空间支持额外的哈希表存储。


方法2:摩尔投票法(最佳选择)

摩尔投票法是一种高效的线性时间算法,专门用于解决多数元素问题。

算法步骤:
  1. 初始化一个候选值 candidate 和计数器 count 为 0。
  2. 遍历数组:
    • 如果当前计数为 0,将当前数字设置为候选值 candidate,并将计数器设置为 1。
    • 如果当前数字等于 candidate,计数器加 1。
    • 如果当前数字不等于 candidate,计数器减 1。
  3. 遍历结束时,candidate 即为多数元素。
时间复杂度与空间复杂度:
  • 时间复杂度:O(n),只需遍历数组一次。
  • 空间复杂度:O(1),不需要额外的存储空间。
适用场景

适用于任何规模的数据,且是本问题的最佳解决方案。

摩尔投票法原理解释

摩尔投票法(Boyer-Moore Voting Algorithm)是一种高效的算法,用于在一个数组中找到出现次数超过一半的元素(即 多数元素)。它的核心思想是通过一种计数机制,利用元素的多数性来进行筛选,最终在 O(n) 的时间复杂度内找到目标元素,并且空间复杂度为 O(1)。

问题背景

在一个大小为 n 的数组中,假设存在一个数字的出现次数超过 n / 2,也就是说这个数字是多数元素。摩尔投票法的目标是找出这个元素。通过遍历数组一次并利用投票机制,我们能够在常数空间内找到这个元素。

摩尔投票法的基本原理
  1. 计数器: 摩尔投票法通过维护一个计数器来识别出现次数最多的元素。这个计数器会随着遍历数组而动态调整。

  2. 选举过程

    • 候选人:首先,我们假设某个元素是候选人(candidate),并初始化计数器为 0。
    • 投票规则
      • 如果当前计数器为 0,选择当前元素作为新的候选人,并将计数器设置为 1。
      • 如果当前元素与候选人相同,计数器加 1。
      • 如果当前元素与候选人不同,计数器减 1。

    这种“投票”方式能够抵消一些非多数元素的干扰,并最终得到一个可能是多数元素的候选值。

  3. 计数的终结: 当整个数组遍历完成后,candidate 就是候选的多数元素。由于多数元素的出现次数超过了数组长度的一半,这个候选元素一定就是多数元素。

详细步骤
  1. 初始化

    • candidate(候选元素)初始化为一个任意值。
    • count(计数器)初始化为 0。
  2. 遍历数组

    • 对于数组中的每个元素:
      • 如果 count == 0,选择当前元素作为新的候选元素,并将计数器设为 1。
      • 如果当前元素等于 candidate,则增加计数器。
      • 如果当前元素与 candidate 不同,则减少计数器。
  3. 返回结果

    • 遍历结束后,candidate 即为数组中出现次数最多的元素。
直观解释

假设数组中的多数元素出现次数超过了数组总长度的一半(n/2)。在摩尔投票法中,元素的“投票”机制确保了最多的元素最终会“胜出”。具体来说:

  • 当遇到与当前候选人不同的元素时,我们会减去一个计数,导致非多数元素的出现机会被“削弱”。
  • 只有当某个元素的出现次数非常高时,才可能在整个数组中最终成为唯一的候选人。
举例说明

假设我们有数组:[3, 3, 4, 2, 4, 4, 2, 4, 4]

  • 第一步:candidate = 3, count = 0
    • 看到第一个元素 3count = 1candidate = 3
    • 看到第二个元素 3count = 2candidate = 3
    • 看到第三个元素 4count = 1candidate = 3count--)。
    • 看到第四个元素 2count = 0candidate = 2count = 1)。
    • 看到第五个元素 4count = 2candidate = 4
    • ...
    • 遍历完成后,candidate = 4 是多数元素。
为什么摩尔投票法有效?
  • 由于题目保证了多数元素一定存在,并且它的出现次数超过数组的一半,因此,在摩尔投票法中,不同的元素相互“抵消”掉的次数是对等的,最终剩下的就是多数元素。
  • 当计数器归零时,说明当前候选元素被其他元素“抵消”了,我们就将候选元素换成新的元素,从而不断减少非多数元素的影响,直到最后剩下的候选元素必然是多数元素。

摩尔投票法的优势

  1. 时间复杂度 O(n)

    • 只需要遍历数组一次,因此时间复杂度是 O(n),其中 n 是数组的长度。
  2. 空间复杂度 O(1)

    • 只使用了两个变量:candidatecount,因此空间复杂度是 O(1),不需要额外的空间。
  3. 适用于大规模数据

    • 在大规模数据中,摩尔投票法具有很高的效率,特别是在内存和空间限制较大的情况下,能够以最优的时间和空间复杂度完成任务。

步骤3:C++ 代码实现

使用摩尔投票法解决问题:

#include <iostream>
#include <vector>

using namespace std;

int solution(vector<int> array) {
    // 摩尔投票法
    int candidate = 0; // 候选元素
    int count = 0;      // 计数器

    // 第一次遍历,确定候选元素
    for (int num : array) {
        if (count == 0) {
            candidate = num; // 重置候选元素
            count = 1;       // 初始化计数器
        } else if (num == candidate) {
            count++; // 当前数字等于候选元素,计数器加1
        } else {
            count--; // 当前数字不等于候选元素,计数器减1
        }
    }

    // 此时candidate即为超过一半的数字,直接返回
    return candidate;
}

int main() {
    // 测试用例
    cout << (solution({1, 3, 8, 2, 3, 1, 3, 3, 3}) == 3) << endl; // 输出 1 (True)
    cout << (solution({5, 5, 5, 1, 2, 5, 5}) == 5) << endl;       // 输出 1 (True)
    cout << (solution({9, 9, 9, 9, 8, 9, 8, 8}) == 9) << endl;   // 输出 1 (True)

    return 0;
}
代码解释:
  1. candidate:记录当前的候选多数元素。
  2. count:记录候选元素的计数。
  3. 第一遍遍历:通过计数器逻辑,找出候选元素。
  4. 时间复杂度:O(n),遍历数组一次。
  5. 空间复杂度:O(1),无额外空间开销。

步骤4:通过解决这个问题获得的启发

  1. 算法设计的重要性:摩尔投票法以 O(n) 的时间和 O(1) 的空间高效解决了问题,体现了精妙的算法设计对效率的提升。
  2. 多数性质的利用:当一个元素出现次数超过数组长度的一半时,不需要完全统计,利用其多数性质即可快速筛选。
  3. 扩展应用:摩尔投票法不仅适用于确定多数元素,还可扩展到寻找多于 n/3 次出现的元素(需要两轮计数)。

步骤5:实际应用分析

实际场景:
  1. 舆情分析

    • 在一个讨论群中,找出被提及最多的关键词。例如,在一个由用户输入的评论数据中,快速筛选出出现频率超过一半的品牌名称或产品关键词。
    • 实现方法
      • 将评论数据转化为数组形式,使用摩尔投票法筛选出最多的品牌关键词。
  2. 传感器数据监测

    • 在实时监测数据中,找出传感器的主流输出值,用于检测异常值。例如,某个值的输出频率异常高,可能表示系统进入了稳定状态。
  3. 选举系统

    • 在电子投票中,快速统计获胜的候选人(多数原则)。
实现示例:

在一个评论数据分析系统中,利用哈希表结合摩尔投票法,可以在多个评论字段中高效找出讨论最多的关键词。配合数据库或大数据平台,还可以实时生成分析报告,提升业务决策效率。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2253217.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

[C++设计模式] 为什么需要设计模式?

文章目录 什么是设计模式&#xff1f;为什么需要设计模式&#xff1f;GOF 设计模式再次理解面向对象软件设计固有的复杂性软件设计复杂性的根本原因如何解决复杂性&#xff1f;分解抽象 结构化 VS 面向对象(封装)结构化设计代码示例&#xff1a;面向对象设计代码示例&#xff1…

级联树结构TreeSelect和上级反查

接口返回结构 前端展示格式 前端组件 <template><div ><el-scrollbar height"70vh"><el-tree :data"deptOptions" :props"{ label: label, children: children }" :expand-on-click-node"false":filter-node-me…

Figma入门-自动布局

Figma入门-自动布局 前言 在之前的工作中&#xff0c;大家的原型图都是使用 Axure 制作的&#xff0c;印象中 Figma 一直是个专业设计软件。 最近&#xff0c;很多产品朋友告诉我&#xff0c;很多原型图都开始用Figma制作了&#xff0c;并且很多组件都是内置的&#xff0c;对…

【Unity基础】使用InputSystem实现物体跳跃

要在Unity中使用 InputSystem 实现小球按空格键跳起的效果&#xff0c;可以按照以下步骤进行&#xff1a; 1. 安装 InputSystem 包 首先&#xff0c;确保你已经安装了 Input System 包。你可以通过以下步骤安装&#xff1a; 打开 Unity 编辑器&#xff0c;点击菜单 Window -…

【ArkTS】使用AVRecorder录制音频 --内附录音机开发详细代码

系列文章目录 【ArkTS】关于ForEach的第三个参数键值 【ArkTS】“一篇带你读懂ForEach和LazyForEach” 【小白拓展】 【ArkTS】“一篇带你掌握TaskPool与Worker两种多线程并发方案” 【ArkTS】 一篇带你掌握“语音转文字技术” --内附详细代码 【ArkTS】技能提高–“用户授权”…

一种多功能调试工具设计方案开源

一种多功能调试工具设计方案开源 设计初衷设计方案具体实现HUB芯片采用沁恒微CH339W。TF卡功能网口功能SPI功能IIC功能JTAG功能下行USB接口 安路FPGA烧录器功能Xilinx FPGA烧录器功能Jlink OB功能串口功能RS232串口RS485和RS422串口自适应接口 CAN功能烧录器功能 目前进度后续计…

浏览器的事件循环机制

浏览器和Node的事件循环机制 引言浏览器的事件循环机制 引言 由于JS是单线程的脚本语言&#xff0c;所以在同一时间只能做一件事情&#xff0c;当遇到多个任务时&#xff0c;我们不可能一直等待任务完成&#xff0c;这会造成巨大的资源浪费。为了协调时间&#xff0c;用户交互…

Zabbix添加防火墙温度监控值实战

我们在Zabbix监控系统会监控诸如Server、network device、application等实例&#xff0c;通常我们在监控某个具体产品时&#xff0c;我们会找到具体的监控模板&#xff0c;在设备添加到平台以后&#xff0c;将模板链接到该设备&#xff0c;但很多时候我们企业内部的设备是没有标…

【k8s】创建基于sa的token的kubeconfig

需求 创建一个基于sa的token的kubeconfig文件&#xff0c;并用这个文件来访问集群。 具体创建sa 和sa的token请参考文章: 【k8s】给ServiceAccount 创建关联的 Secrets-CSDN博客 创建sa apiVersion: rbac.authorization.k8s.io/v1 kind: Role metadata:namespace: jtkjdevnam…

Fastapi + vue3 自动化测试平台---移动端App自动化篇

概述 好久写文章了&#xff0c;专注于新框架&#xff0c;新UI界面的实践&#xff0c;废话不多说&#xff0c;开搞 技术架构 后端&#xff1a; Fastapi Airtest multiprocessing 前端&#xff1a; 基于 Vue3、Vite、TypeScript、Pinia、Pinia持久化插件、Unocss 和 Elemen…

Apache Doris 现行版本 Docker-Compose 运行教程

特别注意&#xff01;Doris On Docker 部署方式仅限于开发环境或者功能测试环境&#xff0c;不建议生产环境部署&#xff01; 如有生产环境或性能测试集群部署诉求&#xff0c;请使用裸机/虚机部署或K8S Operator部署方案&#xff01; 原文阅读&#xff1a;Apache Doris 现行版…

Docker的彻底删除与重新安装(ubuntu22.04)

Docker的彻底删除与重新安装&#xff08;ubuntu22.04&#xff09; 一、首先我们彻底删除Docker1、删除docker及安装时自动安装的所有包2、删除无用的相关的配置文件3、删除相关插件4、删除docker的相关配置和目录 二、重新安装1、添加 Docker 的官方 GPG 密钥&#xff1a;2、将…

Nginx学习-安装以及基本的使用

一、背景 Nginx是一个很强大的高性能Web和反向代理服务&#xff0c;也是一种轻量级的Web服务器&#xff0c;可以作为独立的服务器部署网站&#xff0c;应用非常广泛&#xff0c;特别是现在前后端分离的情况下。而在开发过程中&#xff0c;我们常常需要在window系统下使用Nginx…

力扣hot100道【贪心算法后续解题方法心得】(三)

力扣hot100道【贪心算法后续解题方法心得】 十四、贪心算法关键解题思路1、买卖股票的最佳时机2、跳跃游戏3、跳跃游戏 | |4、划分字母区间 十五、动态规划什么是动态规划&#xff1f;关键解题思路和步骤1、打家劫舍2、01背包问题3、完全平方式4、零钱兑换5、单词拆分6、最长递…

系统--线程互斥

1、相关背景知识 临界资源多线程、多执行流共享的资源,就叫做临界资源临界区每个线程内部,访问临界资源的代码互斥在任何时刻,保证有且只有一个执行流进入临界区,访问临界资源,对临界资源起到保护作用原子性不会被任何调度机制打断的操作,该操作只有两态,要么完成,要么…

Qt桌面应用开发 第十天(综合项目二 翻金币)

目录 1.主场景搭建 1.1重载绘制事件&#xff0c;绘制背景图和标题图片 1.2设置窗口标题&#xff0c;大小&#xff0c;图片 1.3退出按钮对应关闭窗口&#xff0c;连接信号 2.开始按钮创建 2.1封装MyPushButton类 2.2加载按钮上的图片 3.开始按钮跳跃效果 3.1按钮向上跳…

getchar()

getchar():从计算机终端&#xff08;一般是键盘&#xff09;输入一个字符 1、getchar返回的是字符的ASCII码值&#xff08;整数&#xff09;。 2、getchar在读取结束或者失败的时候&#xff0c;会返回EOF 输入密码并确认&#xff1a; scanf读取\n之前的内容即12345678 回车符…

linux 获取公网流量 tcpdump + python + C++

前言 需求为&#xff0c;统计linux上得上下行公网流量&#xff0c;常规得命令如iftop 、sar、ifstat、nload等只能获取流量得大小&#xff0c;不能区分公私网&#xff0c;所以需要通过抓取网络包并排除私网段才能拿到公网流量。下面提供了一些有效得解决思路&#xff0c;提供了…

Node.js:开发和生产之间的区别

Node.js 中的开发和生产没有区别&#xff0c;即&#xff0c;你无需应用任何特定设置即可使 Node.js 在生产配置中工作。但是&#xff0c;npm 注册表中的一些库会识别使用 NODE_ENV 变量并将其默认为 development 设置。始终在设置了 NODE_ENVproduction 的情况下运行 Node.js。…

KAN-Transfomer——基于新型神经网络KAN的时间序列预测

1.数据集介绍 ETT(电变压器温度)&#xff1a;由两个小时级数据集&#xff08;ETTh&#xff09;和两个 15 分钟级数据集&#xff08;ETTm&#xff09;组成。它们中的每一个都包含 2016 年 7 月至 2018 年 7 月的七种石油和电力变压器的负载特征。 traffic(交通) &#xff1a;描…