腾讯面试题,给你10分钟时间,根据上排给出十个数,在其下排填出对应的十个数

题目:

给你10分钟时间,根据上排给出十个数,在其下排填出对应的十个数

要求下排每个数都是先前上排那十个数在下排出现的次数。
上排的十个数如下:
【0,1,2,3,4,5,6,7,8,9】
举一个例子,
数值: 【 0,1,2,3,4,5,6,7,8,9 】
分配: 【 6,2,1,0,0,0,1,0,0,0 】
0在下排出现了6次,
1在下排出现了2次,
2在下排出现了1次,
3在下排出现了0次....
我一开始看到这道题的时候,真是手足无措.实在是没有什么特别好的办法,只能用蛮力法想解决这道题.时间效率比较低.
蛮力法的切入点是什么,这需要好好想一想.
以上面的例子为例:
0在下排出现了6次,即下排有6个0,有2个1,有1个2,有1个6.
仔细观察,可以发现一个共同点:
对于一个数组A[n],下排的数字总和为n.
可以由之前的字符的全排列中找到灵感.
因此可以定义一个函数ArrayF(int* A,int n,int Sum),这个函数的功能是:使得A[0]+A[1]+A[2]+….+A[n-1]=Sum.其中A[i]=m,i=0,1,2,3….n-1,0<m<n-1.
这样子就可以用分治法来解决这个问题了.
假设A[n-1]取值i,则i的可能性是:0,1,2,3,4……n-1.则余下来的n-1个元素的数组就可以调用ArrayF(A,n-1,Sum-i)来解决.
递推式:
F(A[n],Sum)=:(A[0]=Sum) n==1
F(A[n],Sum)=:(A[n-1]=i)+F(A[n-1],Sum-i) n>1 ,i=0,1,2,3…..

由上面的递推式容易写出如下的递归函数.

void ArrayF(int* A,int n,int Sum)
{
	if(!A || n < 1 || Sum < 1)//处理异常,A==NULL,n <=0,Sum<1 
		return ;
	if( n==1 )
	{
		A[0]=Sum;
		for(int i=0;i<Len;++i)
			cout<<A[i]<<' ';
		cout<<endl;
	}
	else
	{
		for(int i=0;i<=Sum;++i)
		{
			A[n-1]=i;
			ArrayF(A,n-1,Sum-i);
		}
	}
}
由上面的函数求出所有的可能输出之后,再写一个函数判断输出序列是否满足条件即可.

时间复杂度为o(n^2),也可以用一个哈希表降低时间复杂度,但是,那样空间复杂度将会是o(n),时间复杂度是o(n).

bool isLegal(int* A,int n)
{
	for(int i=0;i<n;++i)
	{
		int count=0;
		for(int j=0;j<n;++j)
		{
			if(i==A[j])
				++count;
		}
		if(A[i] != count)
			return false;
	}
	return true;
}
完整代码如下:
#include<iostream>
using namespace std;
const int Len = 4;
bool isLegal(int* A,int n)
{
	for(int i=0;i<n;++i)
	{
		int count=0;
		for(int j=0;j<n;++j)
		{
			if(i==A[j])
				++count;
		}
		if(A[i] != count)
			return false;
	}
	return true;
}
void ArrayF(int* A,int n,int Sum)
{
	if(!A || n < 1 || Sum < 1)//处理异常,A==NULL,n <=0,Sum<1 
		return ;
	if( n==1 )
	{
		A[0]=Sum;
		if(isLegal(A,Len))
		{
			for(int i=0;i<Len;++i)
				cout<<A[i]<<' ';
			cout<<endl;
		}
	}
	else
	{
		for(int i=0;i<=Sum;++i)
		{
			A[n-1]=i;
			ArrayF(A,n-1,Sum-i);
		}
	}
}
void main()
{
	int A[20]={0};
	ArrayF(A,Len,Len);
}


你可能感兴趣的:(编程,算法,递归,腾讯,面试题)