C++二分查找算法:数组中占绝大多数的元素

题目

设计一个数据结构,有效地找到给定子数组的 多数元素 。
子数组的 多数元素 是在子数组中出现 threshold 次数或次数以上的元素。
实现 MajorityChecker 类:
MajorityChecker(int[] arr) 会用给定的数组 arr 对 MajorityChecker 初始化。
int query(int left, int right, int threshold) 返回子数组中的元素 arr[left…right] 至少出现 threshold 次数,如果不存在这样的元素则返回 -1。
示例 1:
输入:
[“MajorityChecker”, “query”, “query”, “query”]
[[[1, 1, 2, 2, 1, 1]], [0, 5, 4], [0, 3, 3], [2, 3, 2]]
输出:
[null, 1, -1, 2]
解释:
MajorityChecker majorityChecker = new MajorityChecker([1,1,2,2,1,1]);
majorityChecker.query(0,5,4); // 返回 1
majorityChecker.query(0,3,3); // 返回 -1
majorityChecker.query(2,3,2); // 返回 2
参数范围
1 <= arr.length <= 2 * 104
1 <= arr[i] <= 2 * 104
0 <= left <= right < arr.length
threshold <= right - left + 1
2 * threshold > right - left + 1
调用 query 的次数最多为 104

分析

时间复杂度

O(nsqrt(n)log(sqrt(n))

分两种情况分别讨论。

threshold <= 100

说明 right - left + 1 < 200。直接遍历arr[left,right],统计众数。

threshold > 100

出现次数超过100的数,不会超过200个。记录这些数的索引。然后二分查找[0,right+1)的数量和[0,left)的数量,两者相减就是nums[left,right]中此数的数量。

变量解释

lensqrt(数组长度)代替100
m_vMoreValues记录出现次数超过len的数
m_vValueIndexs记录各数的索引,比如:m_vValueIndexs[3]记录所有3的索引。

可以用摩尔投票

稍稍降低空间复杂度

代码

核心代码

class MajorityChecker {
public:
MajorityChecker(vector& arr) {
m_arr = arr;
m_c = arr.size();
m_len = sqrt(m_c);
const int iMax = *std::max_element(arr.begin(),arr.end());
m_vValueIndexs.resize(iMax+1);
for (int i = 0 ; i < m_c ;i++)
{
const auto& n = arr[i];
m_vValueIndexs[n].emplace_back(i);
}
for (int i = 0; i <= iMax; i++)
{
if (m_vValueIndexs[i].size() >= m_len)
{
m_vMoreValues.emplace_back(i);
}
}
}
int query(int left, int right, int threshold) {
if (threshold >= m_len)
{
for (const auto n : m_vMoreValues)
{
//[0,left)的数量
auto it1 = std::lower_bound(m_vValueIndexs[n].begin(), m_vValueIndexs[n].end(), left);
//[0,right+1)的数量
auto it2 = std::lower_bound(m_vValueIndexs[n].begin(), m_vValueIndexs[n].end(), right+1);
if (it2 - it1 >= threshold)
{
return n;
}
}
return -1;
}
std::unordered_map<int, int> mValueNum;
for (int i = left; i <= right; i++)
{
mValueNum[m_arr[i]]++;
}
for (const auto it : mValueNum)
{
if (it.second >= threshold)
{
return it.first;
}
}
return -1;
}
vector m_arr;
vector<vector> m_vValueIndexs;
vector m_vMoreValues;
int m_c;
int m_len;
};

测试用例

template
void Assert(const T& t1, const T& t2)
{
assert(t1 == t2);
}

template
void Assert(const vector& v1, const vector& v2)
{
if (v1.size() != v2.size())
{
assert(false);
return;
}
for (int i = 0; i < v1.size(); i++)
{
Assert(v1[i], v2[i]);
}
}

int main()
{
vector nums = { 1, 1, 2, 2, 1, 1 };
MajorityChecker majorityChecker(nums);
int res = majorityChecker.query(0, 5, 4); // 返回 1
assert(1 , res);
majorityChecker.query(0, 3, 3); // 返回 -1
assert(-1, res);
majorityChecker.query(2, 3, 2); // 返回 2
assert(2, res);

//CConsole::Out(res);

}

2023年3月旧代码

class MajorityChecker {
public:
MajorityChecker(vector& arr) :m_iNumRange(sqrt(arr.size()) * 2), m_c(arr.size()), m_arr(arr)
{
Init(arr);
}
void Init(const vector& arr)
{
std::unordered_map<int, int> mValueNums;
for (const auto& a : arr)
{
mValueNums[a]++;
}
for (const auto& it : mValueNums)
{
if (it.second <= m_iNumRange)
{
continue;
}
m_vValues.emplace_back(it.first);
m_vValueIndexs.emplace_back();
m_vValueIndexs.back().emplace_back(0);
for (int i = 0; i < m_c; i++)
{
int iSame = arr[i] == it.first;
m_vValueIndexs.back().emplace_back(iSame + m_vValueIndexs.back().back());
}
}
}
int query(int left, int right, int threshold) {
const int len = right - left + 1;
//直接读取缓存
if (threshold > m_iNumRange)
{
for (int i = 0; i < m_vValueIndexs.size(); i++)
{
const int iNum = m_vValueIndexs[i][right + 1] - m_vValueIndexs[i][left];
if (iNum >= threshold)
{
return m_vValues[i];
}
}
return -1;
}
//暴力遍历
int iValue = -1, iNum = 0;
for (int i = left; i <= right; i++)
{
if (m_arr[i] == iValue)
{
iNum++;
}
else
{
if (0 == iNum)
{
iValue = m_arr[i];
iNum = 1;
}
else
{
iNum–;
}
}
}
iNum = 0;
for (int i = left; i <= right; i++)
{
if (m_arr[i] == iValue)
{
iNum++;
}
}
return (iNum >= threshold) ? iValue : -1;
}
//缓存各数值的前缀和
std::vector m_vValues;//m_vValues[i]对应 m_vValueIndexs[i]的值
vector<vector> m_vValueIndexs;
vector m_arr;
const int m_c;
const int m_iNumRange = 1;//众数的数量小于等于m_iNumRange,直接遍历
};

扩展阅读

视频课程

有效学习:明确的目标 及时的反馈 拉伸区(难度合适),可以先学简单的课程,请移步CSDN学院,听白银讲师(也就是鄙人)的讲解。
https://edu.csdn.net/course/detail/38771

如何你想快

速形成战斗了,为老板分忧,请学习C#入职培训、C++入职培训等课程
https://edu.csdn.net/lecturer/6176

相关下载

想高屋建瓴的学习算法,请下载《闻缺陷则喜算法册》doc版
https://download.csdn.net/download/he_zhidan/88348653

洒家想对大家说的话
闻缺陷则喜是一个美好的愿望,早发现问题,早修改问题,给老板节约钱。
墨家名称的来源:有所得以墨记之。
如果程序是一条龙,那算法就是他的是睛

测试环境

操作系统:win7 开发环境: VS2019 C++17
或者 操作系统:win10 开发环境:

VS2022 C++17

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

37 _ 贪心算法:如何用贪心算法实现Huffman压缩编码?

基础的数据结构和算法我们基本上学完了,接下来几节,我会讲几种更加基本的算法。它们分别是贪心算法、分治算法、回溯算法、动态规划。更加确切地说,它们应该是算法思想,并不是具体的算法,常用来指导我们设计具体的算法和编码等。 贪心、分治、回溯、动态规划这4个算法思想…

622.设计循环队列(LeetCode)

思路 先确定什么情况为空&#xff0c;什么情况为满。 这里有两种解决方案&#xff0c; 1.留一个空间空置&#xff0c;当rear1 front时 &#xff0c;则队列为满 &#xff08;这里我们选用方案一&#xff09; 2.增加一个size变量记录数据个数&#xff0c;size 0则为空&#xff…

Uniapp导出的iOS应用上架详解

​ 目录 Uniapp导出的iOS应用上架详解 摘要 引言 苹果审核标准 苹果调试 注意事项和建议 总结 摘要 本文将探讨Uniapp导出的iOS应用能否成功上架的问题。我们将从苹果审核标准、性能影响、调试流程等多个方面进行深入分析&#xff0c;以及向开发者提供相关注意事项和建…

【计算机网络笔记】DHCP协议

系列文章目录 什么是计算机网络&#xff1f; 什么是网络协议&#xff1f; 计算机网络的结构 数据交换之电路交换 数据交换之报文交换和分组交换 分组交换 vs 电路交换 计算机网络性能&#xff08;1&#xff09;——速率、带宽、延迟 计算机网络性能&#xff08;2&#xff09;…

JAVA 中集合取交集

日常工作 经常需要取两个数据集的交集。对常用的List 和Set集合做了一个测试 public static void main(String[] args) {List<Integer> list1 Lists.newArrayList();List<Integer> list2 Lists.newArrayList();Set<Integer> set3 Sets.newHashSet();Set&l…

优秀智慧园区案例 - 重庆AI PARK智慧创意园区,先进智慧园区建设方案经验

一、项目背景 1、智慧园区是国家实现经济增长、产业升级的载体 智慧园区建设是城市智慧化创新发展的核心&#xff0c;在数智化升级和低碳化转型的经济发展双引擎的驱动下&#xff0c;十四五、数字经济的政策大力支持&#xff0c;以及人工智能、5G、大数据、区块链等技术的不断…

ubuntu中cuda12.1配置(之前存在11.1版本的cuda)(同时配置两个版本)

ubuntu中cuda12.1配置 由于YOLOv8项目中Pytorch版本需要cuda12.1版本 在官网下载12.1版本的deb包 官网地址 sudo dpkg -i cuda-keyring_1.0-1_all.deb sudo apt-get update sudo apt-get -y install cuda然后需要修改bashrc文件&#xff08;隐藏文件&#xff09; 添加 exp…

Postman实现接口的加密和解密

近期在复习Postman的基础知识&#xff0c;在小破站上跟着百里老师系统复习了一遍&#xff0c;也做了一些笔记&#xff0c;希望可以给大家一点点启发。 1、目前市面上的加密的方式 对称式加密&#xff1a;DES&#xff0c;AES&#xff0c;Base64加密算法 非对称加密&#xff1a…

基于STC12C5A60S2系列1T 8051单片机的数模芯片TLC5615实现数模转换应用

基于STC12C5A60S2系列1T 8051单片的数模芯片TLC5615实现数模转换应用 STC12C5A60S2系列1T 8051单片机管脚图STC12C5A60S2系列1T 8051单片机I/O口各种不同工作模式及配置STC12C5A60S2系列1T 8051单片机I/O口各种不同工作模式介绍数模芯片TLC5615介绍通过按键调节数模芯片TLC5615…

Postman的Cookie鉴权

近期在复习Postman的基础知识&#xff0c;在小破站上跟着百里老师系统复习了一遍&#xff0c;也做了一些笔记&#xff0c;希望可以给大家一点点启发。 一&#xff09;什么是Cookie 定义&#xff1a;存储在客户端的一小段文本信息&#xff0c;格式为键值对的形式. 二&#xff09…

低代码编辑平台后台实现

背景 之前做过一个前端低代码编辑平台&#xff0c;可以实现简单的移动端页面组件拖拽编辑&#xff1a; https://github.com/li-car-fei/react-visual-design 最近基于C的oatpp框架实现了一下后台。使用oatpp框架做web后台开发时&#xff0c;发现按照官方的示例使用的话&#…

氢原子波函数等概率面的绘制

氢原子波函数等概率面的绘制 归一化后的氢原子波函数

高浓度白酒废水处理需要哪些设备

高浓度白酒废水处理需要的设备包括预处理设备、生物反应器、二级处理设备、消毒装置等。 预处理设备&#xff1a;包括格栅、筛网等&#xff0c;用于去除污水中的大颗粒物和杂质。生物反应器&#xff1a;用于进行生物反应&#xff0c;去除污水中的有机物和氨氮等污染物。二级处…

基于平衡优化器算法优化概率神经网络PNN的分类预测 - 附代码

基于平衡优化器算法优化概率神经网络PNN的分类预测 - 附代码 文章目录 基于平衡优化器算法优化概率神经网络PNN的分类预测 - 附代码1.PNN网络概述2.变压器故障诊街系统相关背景2.1 模型建立 3.基于平衡优化器优化的PNN网络5.测试结果6.参考文献7.Matlab代码 摘要&#xff1a;针…

Linux 系统编程,Binder 学习,文件访问相关的接口

文章目录 Linux 系统编程&#xff0c;Binder 学习&#xff0c;文件访问相关的接口1.概念2.linux文件结构3.文件描述符4.Linux文件系统的两类常用接口&#xff0c;linux系统内置库函数4.1 open4.2 close4.3 read4.4 write 5.标准I/O库函数5.1 fopen Linux 系统编程&#xff0c;B…

IDEA 高分辨率卡顿优化

VM设置优化 -Dsun.java2d.uiScale.enabledfalse 增加该条设置&#xff0c;关闭高分切换 https://intellij-support.jetbrains.com/hc/en-us/articles/115001260010-Troubleshooting-IDE-scaling-DPI-issues-on-Windows​intellij-support.jetbrains.com/hc/en-us/articles/1…

c语言判断链表是否为循环链表

普通链表与循环链表的区别在于&#xff1a;普通链表的最后一个节点指向为NULL&#xff0c;而循环链表最后一个节点指向该链表中的任意一个节点&#xff0c;如同一个环。循环链表问题引出了一个在链表中很重要的概念&#xff1a;快、慢指针。快、慢指针可以帮助我们解决很多经典…

使用jmeter+ant进行接口自动化测试(数据驱动)

本次接着介绍如何利用apache-ant执行测试用例并生成HTML格式测试报告 ①下载安装 apache-ant-1.9.9&#xff0c;配置环境变量 如下方式检验安装成功 ②安装好ant后&#xff0c;把jmeter中extras目录下的ant-jmeter-1.1.1.jar 文件copy到ant安装目录下的lib文件夹中 ③配置ant…

ssm045基于jsp的精品酒销售管理系统+jsp

ssm045基于jsp的精品酒销售管理系统jsp 交流学习&#xff1a; 更多项目&#xff1a; 全网最全的Java成品项目列表 https://docs.qq.com/doc/DUXdsVlhIdVlsemdX 演示 项目功能演示&#xff1a; ————————————————

247:vue+openlayers 根据坐标显示多边形(3857投影),计算出最大幅宽

第247个 点击查看专栏目录 本示例是演示如何在vue+openlayers项目中根据坐标显示多边形(3857投影),计算出最大幅宽。这里先通过Polygon来显示出多边形,利用getExtent() 获取3857坐标下的最大最小x,y值,通过ransformExtent转换坐标为4326, 通过turf的turf.distance和计算…