找出数组中出现次数大于N/K的所有元素

转载自https://blog.csdn.net/Neo_dot/article/details/80642008
https://blog.csdn.net/u013309870/article/details/69788342
有一个整形数组,长度为n,有一个比较小的数k,求数组中出现次数多于n/k的数字
要求空间复杂度O(k),时间复杂度O(k*n)

思路:每次从数组中删除 K 个不同的数,如果某个数的次数大于 N/K ,这个数最后肯定会剩下来
注意:删除后剩余的数不一定全是次数大于 N/K 的数,例如:{1,2,3} k=2, 删除后数组中还剩余 3,但是 3 的次数为 1 ,因此还要看剩余的数的次数是不是大于 N/K.
下面是数组arr[]={1 ,2 ,3 ,3 ,5 ,2 ,2 ,3 ,3 ,3 ,5 ,6 ,2 ,2 ,2 ,3 , 3}处理的简单过程图:
在这里插入图片描述

#include <iostream>
#include <string>
#include <vector>
#include <map>
#include <algorithm>
using namespace std;

vector<int>  GetNumUpToNK(vector<int> a,int K)
{
	vector<int> res;
	int len = a.size();
	
	if (len == 0)
		return res;

	map<int, int>  Ktemp;//待消map K项

	for (int i = 0; i < len; ++i)
	{
		int atemp = a[i];
		if (Ktemp.find(atemp) != Ktemp.end())//该数在map中
		{
			++Ktemp[atemp];
    	}else //不在就加入map中,并判断map的size是否为K,为K则消除K个不同数,相应计数--
		{
			Ktemp.insert(make_pair(atemp, 1));
			if (Ktemp.size() == K)
			{
				for (auto iter = Ktemp.begin(); iter != Ktemp.end();)
				{
					--((*iter).second);
					if ((*iter).second == 0)
						iter = Ktemp.erase(iter);
					else
						++iter;
				}
			}
		}		
	}


	//此时Ktemp中的元素为备选元素,继续核实。。。。。。
	for (auto it = Ktemp.begin();it!=Ktemp.end();++it)
		(*it).second = 0;
	for (auto c:a)  //使用此方法c为只读
	{
		if (Ktemp.find(c) != Ktemp.end())
		{
			++Ktemp[c];
		}
	}


	for (auto b:Ktemp)
	{
		if (b.second>len/K)
		{
			res.push_back(b.first);
		}
	}

	return res;
}


int main()
{
	vector<int> a = { 7,3,3,7,4,5,4,7,3,4,3,4,7,3,4 };
	vector<int> ress = GetNumUpToNK(a, 3);

	if (ress.empty())
	{
		cout << "无符合要求的元素" << endl;
	}
	else 
	{
		for (auto m : ress)
			cout << m << " ";
		cout << endl;
	}
}
在数学上,任何包含三个或以上不同数的数组中,不可能存在一个既不是最大也不是最小的数,因为至少会有两个数是相同的。但是在计算机科学中,我们可以考虑算法,通过比较找出一个数组中满足条件的数,即使这在数学上不可能实现。 然而,如果我们要找出一个既不是最大也不是最小的数,我们可以假设数组中的数字是不重复的,然后使用一种快速选择算法,比如快速排序的选择过程(QuickSelect),来找到中位数,也就是在排序后位于中间位置的数,这样它既不是最大也不是最小的数。 快速选择算法的基本思想是划分数组,使得划分后的左侧所有元素都不大于右侧所有元素,然后根据目标位置来决定是继续在左侧找还是在右侧找。在最坏情况下,算法的性能是O(n^2),但如果采用随机化策略,平均性能可以达到O(n)。 下面是寻找中位数的快速选择算法的伪码,这个版本是基于快速排序选择过程的简单实现: ``` function QuickSelect(A, left, right, k) if left = right return A[left] pivotIndex <- Partition(A, left, right) if k = pivotIndex return A[k] else if k < pivotIndex return QuickSelect(A, left, pivotIndex - 1, k) else return QuickSelect(A, pivotIndex + 1, right, k) end function function Partition(A, left, right) pivot <- A[right] i <- left for j <- left to right - 1 if A[j] <= pivot swap A[i] with A[j] i <- i + 1 swap A[i] with A[right] return i end function ``` 在这个算法中,`A` 是原始数组,`left` 和 `right` 是数组的左右边界索引,`k` 是目标位置。对于找中位数的问题,`k` 将会是数组长度的中间索引。 在最坏的情况下,比较次数是O(n^2)。但是在实际应用中,通过随机选择枢轴或者使用中位数的中位数作为枢轴等策略可以使得算法的平均性能接近O(n)。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值