C语言算法金手指摩尔投票法手撕绝大多数问题

 更新时间:2022年02月14日 10:06:30   作者:乔乔家的龙龙  
这篇文章主要为大家介绍了C语言算法之金手指摩尔投票法手撕绝大多数问题的示例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助

正片开始

概念

嘛是摩尔投票法?
简单来说就是投票法,算法解决的问题是如何在任意多的候选人,选出获得票数最多的那个。常见的算法是扫描一遍选票,也就是遍历,对每个候选人进行统计的选票进行统计。

那我遍历难道不香吗?

在这里插入图片描述

这里就要讲一下投票法的过人之处

优点

当执行有序情况时,只要找到中位数,然后检查中位数的个数是否超过选票的一半即可。但是当对象的数目不定时,统计选票可能会执行较长时间,相比原来的时间复杂度 O(n) ,可能需运行 O(n^2) 的时间。

针对无序且对象不定的情况,摩尔投票法应运而生。

算法核心

摩尔投票法的关键就是抵消和计数,抵消过程类似于是在进行投票,然后计数我们可以脑补一个情形:当三人中的一人得票数远超其他两人时,我们就可以进行等量对消,消完还有票的自然就是得票数最多的那个,模拟如下:(ppt手残勿喷)

在这里插入图片描述

在这里插入图片描述

实现

基本思路就是由一个计数器维护,在进行比较过程中,不同票消掉,相同票保留,如果消的没有了就直接放进去然后继续上述过程,直到维护对象只剩一个,就是我们要找的最大得票者(众数)。

基于LeetCode真题实践,先看一个初级栗子:

169. 多数元素
给定一个大小为 n 的数组,找到其中的多数元素。多数元素是指在数组中出现次数 大于 ⌊ n/2 ⌋ 的元素。你可以假设数组是非空的,并且给定的数组总是存在多数元素。

示例:
输入:[2,2,1,1,1,2,2]
输出:2

来源:力扣(LeetCode)

我最初的思路是哈希思想,qsort 之后用最大的元素 malloc 一块新的空间,桶排后用 count 进行++,最后输出 count 最大的。有点麻烦而且我忽视了一个最大的问题就是负数的存在,垮掉~

根据我们算法的思路,针对目标数组 nums,首先创建一个变量来执行计数器 count 再创建一个新数组 a 进行比对,因为始终是目标数组的内部元素比较,我可以直接把 nums 首元素赋给 a ,比较时从第二个元素开始和 a 比较,如果相同,count ++;不同消掉,count --;没有了就往里拿。

int majorityElement(int* nums, int numsSize){
    int count = 1;
    int a = nums[0];
    for(int i =1;i<numsSize;i++)
    {
        if(nums[i]==a)
        {
            count++;
        }
        else
        {
            count--;
        }
        if(count==0)
        {
        a = nums[i+1];
        }
    }
    return a;
}

格局抬高

现在整一道硬菜,直接上升级版:
229. 求众数 II
给定一个大小为 n 的整数数组,找出其中所有出现超过 ⌊ n/3 ⌋ 次的元素。

示例 :
输入:[1,1,1,3,3,2,2,2]
输出:[1,2]

还是那句话,题目越少眼泪越饱,短小精悍的题 nnd 硬磨了我一个下午,桶是肯定桶不了的,哈希又没学,不做吧心里太不舒服,这里就又有我摩尔投票法的一席之地了

注意,题目给的是超过 n/3 次的元素,这很重要,其实就是在暗示我们结果至多只会有三种情况:没有众数或者一个众数或者两个众数;但是头疼的是咱之前的摩尔投票法好像行不通,因为这里对象不定,如果出现了两个众数我的 “ 票 ” 该怎么投?

将之前的格局打开,我们可以将所有数字分为两类,> n/3 的元素 和 <= n/3 的元素,其中大于 n/3 的元素最多只有两个。因此可以设置三个变量,进行相对抵消,这里我们不妨再引入一个容器 b,再用一个新的计数器 count2 来进行维护,当三个元素相同时,count++,不同就抵消,为 0 就用把这个数放进去,基本思想和上面是差不多的:

    int a = nums[0];
	int b = nums[1];
	int count1, count2 = 0;
	for (int i = 0; i < numsSize; i++)
	{
		if (a == nums[i])
		{
			count1++;
			continue;
		}
		else if (b == nums[i])
		{
			count2++;
			continue;
		}
		else
		{
			count1--;
			count2--;
		}
		if (count1 < 0)
		{
			a = nums[i];
			count2++;
			count1 = 1;
		}
		if (count2 < 0)
		{
			b = nums[i];
			count1++;
			count2 = 1;
		}
	}

还没完,因为数组可能存在一个众数或者没有众数的情况,我们还需要再次遍历来统计我们筛选的众数的出现次数是否符合题目要求的大于n/3 以及排除数组为空或单项的情况:

    count1 = 0;
	count2 = 0;
	for (int i = 0; i < numsSize; i++)
	{
		if (a == nums[i])
		{
			count1++;
		}
	    else if (b == nums[i])
		{
			count2++;
		}
	}
		if (numsSize <= 1)
	{
		*returnSize = numsSize;
		return nums;
	}

最后直接依次放入一块新的空间再返回即可,全部代码如下:

int* majorityElement(int* nums, int numsSize, int* returnSize) {
	if (numsSize <= 1)
	{
		*returnSize = numsSize;
		return nums;
	}
	int a = nums[0];
	int b = nums[1];
	int count1, count2 = 0;
	for (int i = 0; i < numsSize; i++)
	{
		if (a == nums[i])
		{
			count1++;
			continue;
		}
		else if (b == nums[i])
		{
			count2++;
			continue;
		}
		else
		{
			count1--;
			count2--;
		}
		if (count1 < 0)
		{
			a = nums[i];
			count2++;
			count1 = 1;
		}
		if (count2 < 0)
		{
			b = nums[i];
			count1++;
			count2 = 1;
		}

	}
	count1 = 0;
	count2 = 0;
	for (int i = 0; i < numsSize; i++)
	{
		if (a == nums[i])
		{
			count1++;
		}
	    else if (b == nums[i])
		{
			count2++;
		}
	}
	int* c = (int*)malloc(sizeof(int) * 2);
    *returnSize = 0;
	if (count1 > numsSize / 3)
	{
		c[(*returnSize)++] = a;
	}
	if (count2 > numsSize / 3)
	{
		c[(*returnSize)++] = b;
	}
	return c;
}

家人们明白了吗,那今天就到这里,摸了。

以上就是C语言算法金手指摩尔投票法手撕绝大多数问题的详细内容,更多关于C语言摩尔投票算法的资料请关注脚本之家其它相关文章!

相关文章

  • VSCode (Visual Studio Code) V1.43.0下载并设置成中文语言的方法

    VSCode (Visual Studio Code) V1.43.0下载并设置成中文语言的方法

    Visual Studio Code是一款免费开源的现代化轻量级代码编辑器,支持语法高亮、智能代码补全、自定义热键、括号匹配、代码片段、代码对比 Diff、GIT 等特性,这篇文章主要介绍了VSCode (Visual Studio Code) V1.43.0下载并设置成中文语言,需要的朋友可以参考下
    2020-03-03
  • C语言实现高精度的加法

    C语言实现高精度的加法

    这篇文章主要为大家详细介绍了C语言实现高精度的加法,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2021-05-05
  • C++实现LeetCode(45.跳跃游戏之二)

    C++实现LeetCode(45.跳跃游戏之二)

    这篇文章主要介绍了C++实现LeetCode(45.跳跃游戏之二),本篇文章通过简要的案例,讲解了该项技术的了解与使用,以下就是详细内容,需要的朋友可以参考下
    2021-07-07
  • C++利用ImGUI绘制D3D外部菜单

    C++利用ImGUI绘制D3D外部菜单

    ImGUI 它是与平台无关的C++轻量级跨平台图形界面库,没有任何第三方依赖,可以将ImGUI的源码直接加到项目中使用。本文将利用ImGUI绘制D3D外部菜单,需要的可以参考一下
    2022-09-09
  • C语言实现酒店管理系统

    C语言实现酒店管理系统

    这篇文章主要为大家详细介绍了C语言实现酒店管理系统,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2020-03-03
  • windows下用c++获取本机ip地址的三种方法

    windows下用c++获取本机ip地址的三种方法

    工作过程中遇到一个需求,需要获取本机ip地址,同时获取本机网络连接情况,即网线是否连接,经过多番搜索,本文给大家介绍了3种方案,通过代码示例介绍的非常详细,需要的朋友可以参考下
    2023-11-11
  • C++ Boost Phoenix库示例分析使用

    C++ Boost Phoenix库示例分析使用

    Boost是为C++语言标准库提供扩展的一些C++程序库的总称。Boost库是一个可移植、提供源代码的C++库,作为标准库的后备,是C++标准化进程的开发引擎之一,是为C++语言标准库提供扩展的一些C++程序库的总称
    2022-11-11
  • vscode工程中c_cpp_properties.json文件作用详细说明

    vscode工程中c_cpp_properties.json文件作用详细说明

    c_cpp_properties.json是Visual Studio Code的一个配置文件,用于定义C/C++编译器的路径、默认包含路径和预处理器定义,这篇文章主要给大家介绍了关于vscode工程中c_cpp_properties.json文件作用详细说明的相关资料,需要的朋友可以参考下
    2024-08-08
  • 深入解析C++编程中基类与基类的继承的相关知识

    深入解析C++编程中基类与基类的继承的相关知识

    这篇文章主要介绍了C++编程中基类与基类的继承的相关知识,包括多个基类继承与虚拟基类等重要知识,需要的朋友可以参考下
    2016-01-01
  • Qt QCompleter自动补全的实现

    Qt QCompleter自动补全的实现

    本文主要介绍了Qt QCompleter自动补全的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2022-04-04

最新评论