无序数组:删除出现超过k次的元素

无序数组:删除出现超过k次的元素

相对顺序可以和原数组不同

assert:当 i 指i针指向第 i 个元素的时候,保证前 i -1 个元素都是满足条件的,即,需要保留的。
所以:假如前 i - 1 个元素中有与第 i 个元素相同的,保留第 i 个元素,否则扫描数组,数数。

方法一:

若出现次数小于k次,将所有和当前元素相等的元素都移到数组的末尾,当然,和a[i]相等的只可能在 i 后面出现。

void filter_1(int *a, int& n, int countThreshold)
{
	int i = 0;
	while (i < n)
	{
		// assert:第0-i-1个元素都是要保留的元素
		int count = 1;
		for (int j = 0; j < i; j++)
		{
			if (a[j] == a[i])
			{
				count = countThreshold;
				break;
			}
		}
		//若i在前面出现过,count=countThreshold-->不会进入这个循环
		//数数
		for (int j = i + 1; j < n && count < countThreshold; j++)
			 if (a[j] == a[i])
				count++;
                 // count += a[j] == a[i];

		if (count < countThreshold) 
		//去掉所有的该元素
		{
			int j = i;
			int m = n - 1;//保留当前n的值
			n -= cnt;
			while (cnt > 0) {
				while (a[m] == a[i])m--;
				//m指向最后一个不等于a[i]的下标
				while (a[j] != a[i])j++;
				//寻找下一个等于a[i]的元素
				//j指向下一个等于a[i]的元素
				a[j] = a[m--];
				cnt--;
			}
		}
		else
			i++;//否则,检查下一个元素
	}
}

方法二:

新建一个大小为 k 的数组
locs[k] = j;表示,当前a[i]这个元素,出现第k次,是在位置j。
比如:当前 i = 3, a[i] = 4, 且第 5,7 个元素都是4,则
locs[0] = 3, locs[1] = 5, locs[2] = 7。

void filter_1B(int *a, int& n, int countThreshold)
{
	int *locs = new int[countThreshold];
	int i = 0;
	while (i < n)
	{
		// assert: elements in a[0..i-1] appear >= countThreshold times in a[]
		// Determine how many times a[i] appears in a[] and save the indexes in locs[].
		locs[0] = i;
		int count = 1;
		for (int j = 0; j < i; j++)
		{
			if (a[j] == a[i])
			{
				count = countThreshold;
				break;
			}
		}
		for (int j = i + 1; j < n && count < countThreshold; j++)
			 if (a[j] == a[i])
			 {
				locs[count] = j;
				count++;
			 }
//到此为止与上一种相同
		if (count < countThreshold) 
		{   
			int t = a[i];
			int j = n - 1;  // j是最后一个部等于t的元素的下标
			for (int k = 0; k < count && locs[k] < j; k++)
			{
				while (j > locs[k] && a[j] == t)
				//1. j是最后一个不等于 a[i] 的
				//2. 当前正在移除第k个a[i],所以j应在该元素的后面
				//即:locs[k],所以j>locs[k]
					j--;//找j
				a[locs[k]] = a[j--];  
			}
			n -= count;
		}
		else
			i++;
	}
	delete[] locs;
}

这两种方法虽然代码比较复杂,但比单纯的两重循环要少一些扫描

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值