C语言刷题之摩尔投票法

news2024/9/26 5:17:01

目录

1.引入

2.摩尔投票算法

3.基本步骤

摩尔投票法分为两个阶段:

        1.抵消阶段

         2.检验阶段

4.代码实现

5.扩展沿伸

 6.总结


1.引入

        我们来看一个问题:

假设有一个无序数组长度为n,要求找出其中出现次数超过n/2的数,要求时间复杂度为O(n),空间复杂度为O(1).


第一种方法就是遍历数组的每一个元素,统计出现的次数,但时间复杂度显然不符合要求。第二种方法是排序,我们可以先对数组进行排序,然后判断中间的数是否满足条件,这种做法时间复杂度最低为O(nlogn)。

第三种做法是用哈希表记录元素出现的次数,然后遍历哈希表寻找满足条件的元素,此时时间复杂度为O(n),空间复杂度为O(n)。


显然以上三种做法都不能同时符合题目空间复杂度和时间复杂度的要求,下面我们将介绍一种主要解决多数元素的一种算法---摩尔投票算法

2.摩尔投票算法

        摩尔投票法又称多数投票法,主要用于解决一个数组中的众数(要求数量超过数组长度的二分之一)的问题。它的原理如下:

我们将数组的元素想象成一张张选票,数字代表候选人的序号,每次从数组中取两个元素,如果两个元素相同,则选票数进行累加;如果不相同,则选票进行抵消,直到遍历完整个数组。如果数组中存在符合要求的候选人,则最后剩下的选票一定是最终候选人的序号。(极限一换一规则)

3.基本步骤

摩尔投票法分为两个阶段:

        1.抵消阶段

        本阶段将数组的元素(候选人)进行抵消。我们先定义候选人major为第一个元素,然后设置计数器count为1,向后进行遍历,当后续元素和major相等,则count++,否则count--。如果count为0时,就将候选人major改为下一个元素,count置1,以此循环直到数组遍历完毕。如果数组中存在出现次数大于n/2的元素,则最后major一定是这个元素。动图如下:

         2.检验阶段

        由于我们不知道数组是否存在符合条件的多数元素,所以需要对最后的major进行检验。例如数组为【1,2,3】,最后求出的major为3,但3显然不是数组的多数元素。所以还需遍历一遍数组判断major出现次数是否大于n/2。


4.代码实现

        回到我们文章开头的题目,这道题出处为LeetCode第169题,代码如下:
 

int majorityElement(int* nums, int numsSize)
{
	//抵消阶段
	int count = 1;
	int major = nums[0];
	for (int i = 1; i < numsSize; i++)
	{
		if (count != 0)
		{
			if (nums[i] == major)
			{
				count++;
			}
			else
			{
				count--;
			}
		}
		else
		{
			major = nums[i];
			count = 1;
		}
	}
	
	//检验阶段
	int n = 0;
	for (int i = 0; i < numsSize; i++)
	{
		if (major == nums[i])
		{
			n++;
		}
	}
	if (n > numsSize / 2)
	{
		return major;
	}
	else
	{
		return -1;
	}
}

5.扩展沿伸

        我们先来看题目,本题是LeetCode第229题,是多数元素的改编题:

         本题的本质还是求众数,通过题目我们可以得知,出现次数超过n/3次的元素至多只有两个。因此我们可以将摩尔投票法进行扩展,步骤如下:

1.定义两个候选人,用major1和major2两个变量维护,然后设置两个计数器count1和count2,向后遍历数组。

2.当和major1或major2相等时,将count1或count2加1,当不等于major1和major2时将count1和count2都减1,也就是三者抵消。当count1或count2为0时则将major1或major2改为下一个候选人(数组元素)。

3.当遍历完数组后,再对major1和major2进行检验,即可求出答案。

         代码如下:

int* majorityElement(int* nums, int numsSize, int* returnSize)
{
	if (nums == NULL || numsSize <= 1)    //数组为空或最多只有一个元素
	{
		*returnSize = numsSize;
		return nums;
	}
	//抵消阶段
	int major1 = nums[0];   //候选人1
	int major2 = nums[1];   //候选人2
	int count1 = 0;         //票数
	int count2 = 0;         //票数
	for (int i = 0; i < numsSize; i++)
	{
		if (nums[i] == major1)
		{
			count1++;
		}
		else if (nums[i] == major2)
		{
			count2++;
		}
		else if (count1 == 0)
		{
			major1 = nums[i];
			count1 = 1;
		}
		else if (count2 == 0)
		{
			major2 = nums[i];
			count2 = 1;
		}
		else
		{
			count1--;
			count2--;
		}
	}

	//检验阶段
	int n1 = 0, n2 = 0;
	*returnSize = 0;
	int* ret = (int*)malloc(2 * sizeof(int));
	for (int i = 0; i < numsSize; i++)
	{
		if (nums[i] == major1)
		{
			n1++;
		}
		else if (nums[i] == major2)
		{
			n2++;
		}
	}
	if (n1 > numsSize / 3)      //major1符合要求
	{
		ret[*returnSize] = major1;
		(*returnSize)++;        
	}
	if (n2 > numsSize / 3)     //major2符合要求
	{
		ret[*returnSize] = major2;
		(*returnSize)++;
	}
	return ret;
}

 6.总结

通过以上两道题目,我们了解了摩尔投票算法适用于寻找一个数组中出现次数超过一定比例的元素。

当题目要找出出现次数超过1/2的元素,则至多有1个元素满足

当题目要找出出现次数超过1/3的元素,则至多有2个元素满足

当题目要找出出现次数超过1/4的元素,则至多有3个元素满足

当题目要找出出现次数超过1/n的元素,则至多有n-1个元素(n>=2)满足


至多有n个元素满足,我们就用n个变量和n个计数器来维护这n个元素。当数组遍历完后,还需再次检验这n个元素是否满足题目要求。


以上,就是本期全部内容。

制作不易,能否点个赞再走呢qwq

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

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

相关文章

vue3-环境搭建(docker版本)

序 大大小小项目经历无数&#xff0c;之前都是写的vue2的项目&#xff0c;因为项目需要&#xff0c;边学边用vue3&#xff0c;也算能转的开&#xff0c;但心里一直想系统的理顺一下vue3。 看了看极客时间&#xff0c;掘金小课&#xff0c;都没有能达到心里预期的“系统学习”…

免费内网穿透软件一步设置实现外网访问

在工作和生活中&#xff0c;有很多类似内网搭建服务器和外网连接内网的需求&#xff0c; 例如在任何地方都能访问自己家里的主机电脑笔记本上的应用&#xff0c;让出差外网和任何地方都能访问到公司内部局域网的服务器……这些需求我们可以统一用一个方案解决&#xff0c;那就是…

网络编程UDP+TCP

日升时奋斗&#xff0c;日落时自省 目录 1、网络编程基本概念 2、UDP数据报套接字编程 2.1、UDP相关API 2.1.1、DatagramSocket API 2.1.2、DatagramPacket API 2.2、UDP版本服务器 2.3、UDP版本客户端 2.4、UDP连接操作 2.5、翻译业务 2.6、总结 3、TCP流套接字编程 …

【项目实战】一文入门项目中Lombok的常用注解

一、Lombok介绍 1.1 Lombok是什么&#xff1f; 一个Java库&#xff0c;用于简化Java代码。 Lombok是一个非常神奇的 java 类库&#xff0c;会利用注解自动生成 java Bean 中烦人的 Getter、Setting&#xff0c;还能自动生成 logger、ToString、HashCode、Builder 等 java特色…

【GD32F427开发板试用】开发一款网络音乐播放器

本篇文章来自极术社区与兆易创新组织的GD32F427开发板评测活动&#xff0c;更多开发板试用活动请关注极术社区网站。作者&#xff1a;守勤 资源介绍 非常荣幸能够参与到这次GD32F427开发板试用的活动中来&#xff0c;开发板的设计非常简洁&#xff0c;板载了一颗GD32F103C8T6和…

Python中的递归及案例演示

目录 一.什么是递归 二.案例 递归找文件 步骤 os模块中的三个方法 演示 最终代码 三.总结 一.什么是递归 递归在编程中是一种非常重要的算法 递归:即方法(函数)自己调用自己的一种特殊编程写法 如&#xff1a; 函数调用自己&#xff0c;即称之为递归调用。 二.案例 递…

C++ 引用! 他是坤坤也是鸡哥

&#x1f451;专栏内容&#xff1a;C学习笔记⛪个人主页&#xff1a;子夜的星的主页&#x1f495;座右铭&#xff1a;日拱一卒&#xff0c;功不唐捐 目录一、前言二、引用1、引用的概念2、引用的声明3、引用的特性Ⅰ、 引用在定义时必须初始化Ⅱ、 一个变量可以有多个引用Ⅲ、引…

深度学习PyTorch 之 DNN-多分类

前面讲了深度学习&PyTorch 之 DNN-二分类&#xff0c;本节讲一下DNN多分类相关的内容&#xff0c;这里分三步进行演示 结构化数据 我们还是以iris数据集为例&#xff0c;因为这个与前面的流程完全一样&#xff0c;只有在模型定义时有些区别 损失函数不一样 二分类时用的损…

Pollard Rho算法

生日悖论 假设一年有nnn天&#xff0c;房间中有kkk人&#xff0c;每个人的生日在这nnn天中&#xff0c;服从均匀分布&#xff0c;两个人的生日相互独立 问至少要有多少人&#xff0c;才能使其中两个人生日相同的概率达到ppp 解&#xff1a;考虑k≤nk\le nk≤n 设kkk个人生日互…

Spring框架介绍及使用

文章目录1.概述1.1 Spring是什么1.2 Spring 的优势1.3 spring 的体系结构2. IoC 的概念和作用2.1 什么是程序的耦合2.2 IoC容器3. AOP的概念和作用超链接&#xff1a; Spring重点内容学习资料1.概述 1.1 Spring是什么 Spring 是分层的 Java SE/EE 应用 full-stack 轻量级开源…

使用docker-compose搭建Prometheus+Grafana监控系统

一、角色分配 Prometheus 采集数据Grafana 用于图表展示redis_exporter 用于收集redis的metricsnode-exporter 用于收集操作系统和硬件信息的metricscadvisor 用于收集docker的相关metrics 二、安装Docker 可以参考&#xff1a;https://ximeneschen.blog.csdn.net/article/d…

JVM调优实战:to-space exhausted Evacuation Failure

一次线上dubbo问题的定位&#xff0c;进行JVM调优实战。问题线上dubbo接口provider抛出异常&#xff1a;org.apache.dubbo.rpc.RpcException: Failfast invoke providers ... RandomLoadBalance select from all providers ... use dubbo version 2.7.16, but no luck to perfo…

vulnhub DC系列 DC-8

总结&#xff1a;exim4提权 目录 下载地址 漏洞分析 信息收集 网站爆破 后台webshell 提权 下载地址 DC-8.zip (Size: 379 MB)Download: http://www.five86.com/downloads/DC-8.zipDownload (Mirror): https://download.vulnhub.com/dc/DC-8.zip使用方法:解压后&#xff…

Cosmos 基础(二)-- Ignite CLI

官网 DOC GitHub 你的项目值得拥有自己的区块链。 Ignite使开发、增长和启动区块链项目比以往任何时候都更快。 Ignite CLI是一个一体化平台&#xff0c;可以在主权和安全的区块链上构建、启动和维护任何加密应用程序 Install Ignite 一、安装 你可以在基于web的Gitpod…

23种设计模式(七)——桥接模式【单一职责】

文章目录 意图什么时候使用桥接真实世界类比桥接模式的实现桥接模式的优缺点亦称:Bridge 意图 桥接模式是将抽象部分与实现部分分离,使它们都可以独立地变化。它是一种对象结构型模式,又称为柄体(Handle and Body)模式或接口(Interfce)模式。 什么时候使用桥接 1、如果一个…

详解MySQL数据库索引实现机制 - B树和B+树

详解MySQL数据库索引实现机制 - B树和B树1.索引的出现2.hash算法的缺点3.二叉排序树BST4.平衡二叉树AVL5.红黑树6.B树诞生了7.B树1.索引的出现 索引是一种用于快速查询和检索数据的数据结构&#xff0c;其本质可以看成是一种排序好的数据结构。 索引的作用就相当于书的目录。…

(Netty)Handler Pipeline

Handler & Pipeline ChannelHandler 用来处理 Channel 上的各种事件&#xff0c;分为入站、出站两种。所有 ChannelHandler 被连成一串&#xff0c;就是 Pipeline 入站处理器通常是 ChannelInboundHandlerAdapter 的子类&#xff0c;主要用来读取客户端数据&#xff0c;写…

【嵌入式处理器】CPU、MPU、MCU、DSP、SoC、SiP的联系与区别

1、CPU(Central Processing Unit) CPU(Central Processing Unit)&#xff0c;是一台计算机的运算核心和控制核心。CPU由运算器、控制器和寄存器及实现它们之间联系的数据、控制及状态的总线构成。众所周知的三级流水线&#xff1a;取址、译码、执行的对象就是CPU&#xff0c;差…

重学Android之View——TabLayoutMediator解析

重学Android之View——TabLayoutMediator解析 1.前言 在使用TabLayoutViewPager2Fragment的时候&#xff0c;查询别人的使用例子&#xff0c;看到了 TabLayoutMediator这个类&#xff0c;撰写此文&#xff0c;仅当学习思考&#xff0c;本文是在引用material:1.7.0的版本基础…

记2022年秋招经历

自我介绍求职体验求职心得 一、自我介绍 学历普通本科&#xff0c;专业是网络工程&#xff0c;在校期间学习主要的是计算机体系方面的知识&#xff0c;根据课程&#xff0c;自学过前端、后端等内容。包括前端三板斧(htmlcssjs)、常用的前端框架(bootstarp/Vue等&#xff09;&am…