分治法用递归求排列问题

题目如下:

分治法求众数:

给定含有n个元素的多重集合S,每个元素在S中出现的次数称为该元素的重数。多重集S中重数最大的元素称为
众数。例如,S={1,2,2,2,3,5}。多重集S的众数是2,其重数为3。

编程任务:对于给定的由n个自然数组成的多重集S,采用分治算法编程计算S的众数及其重数。

输入格式

第1行多重集S中元素个数n;接下来的一行为集合S,有n个自然数。( n < 1000000 )

输出格式

结果输出:输出2个数,第1个数为众数,第2个为其重数。
当有多个同样重数的众数,优先输出数值更小的数的众数。

输入样例

6
1 2 2 2 3 5

输出样例

2 3

这个题目可以做的方法挺多,但是它要求要用分治法来求解。

思路分析:
1. 先排序

至于排序的算法,我这里直接使用C++里面提供的函数:

sort(vector.begin(), vector.end());

在后续的博文再总结一下排序算法的问题

2. 找中位数与其个数

这一步是最关键的,基本上这个写出来,程序已经算是完成8成了。
以中位数为起点,向两边比较得出中位数的个数,并记录中位数到两边的位置。
这里会定义几个数:

int number;//输入的个数
int largest = 0;//最大的数
int lar_number = 0;//最大的数的个数
//上面几个是全局变量

int l, ll, r, rr;
//l表示最左边,ll表示左边的最右边。r表示右边的最左边,rr表示右边的最右边
//这几个表示求出中位数之后得出的边界,以便下一次的递归。
3.分治递归

在第二步的基础上,我们采用递归方式:

void solve(vector<int> array, int s, int e, int flag)
//这里s表示start起点,e表示end终点,flag用来表示这个递归是在左边还是在右边,因为我们
//可能会遇到右边的中间数刚好跟左边的一样,这个时候只能取左边的。
下面是具体代码:(代码的本质有点重复了,显得比较臃肿,还可以多加改进,希望大家多多交流)
#include <iostream>
#include <vector>
#include <algorithm>

using namespace std;
int number;//输入的个数
int largest = 0;//最大的数
int lar_number = 0;//最大的数的个数

void solve(vector<int> array, int s, int e, int flag) {
	if ((e - s) + 1 >= lar_number) {
		int mid_value = array[(s + e) / 2];
		int l = 0, ll = (s + e) / 2 - 1, r = (s + e) / 2 + 1, rr = e;

		//接下来定义中位数的个数
		int mid_number = 1;
		//这里算最左边的
		for (int i = ll; i >= 0; i--) {
			if (array[i] == mid_value) {
				//mll减一,mid_nuber加一
				ll--;
				mid_number++;
			}
			else
				break;
		}
		//现在算最右边的:
		for (int i = r; i <= rr; i++) {
			if (array[i] == mid_value) {
				//r加一,lar_number也加一
				r++;
				mid_number++;
			}
			else
				break;
		}
		if (mid_number > lar_number) {
				largest = mid_value;
				lar_number = mid_number;
		}
		else {
			if (mid_number == lar_number) {
				if (flag == 1) { //等于1则是左边的,要不然就不用等于了
					largest = mid_value;
					lar_number = mid_number;
				}
			}
		}
		solve(array, l, ll, 1);
		solve(array, r, rr, -1);

	}
	else {
		return;
	}
}


int main() {
	cin >> number;
	vector<int> array(number);
	int in;
	for (int i = 0; i < number; i++) {
		cin >> in;
		array[i] = in;
	}
	sort(array.begin(), array.end());
	int l, ll, r, rr;
	//l表示最左边,ll表示左边的最右边。r表示右边的最左边,rr表示右边的最右边
	l = 0;
	ll = number / 2 - 1;
	r = number / 2 + 1;
	rr = number - 1;
	//初定义largest为中位数, lar_number为1
	largest = array[number / 2];
	lar_number = 1;
	//这里算最左边的
	for (int i = ll; i >= 0; i--) {
		if (array[i] == largest) {
			//ll减一,lar_number加一
			ll--;
			lar_number++;
		}
		else
			break;
	}
	//现在算最右边的:
	for (int i = r; i <= rr; i++) {
		if (array[i] == largest) {
			//r加一,lar_number也加一
			r++;
			lar_number++;
		}
		else
			break;
	}
	solve(array, l, ll, 1);
	solve(array, r, rr, -1);
	cout << largest <<" " << lar_number;
	return 0;
}
  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值