第十一届蓝桥杯 字串排序 我的错误的猜想【自我总结用】

思路+码一共约45分种,最终得分七十分,我知道自己错在哪,好像不怎么能改得了,但混混分应该还行,先占个坑写写思路吧。

首先我的思路基础,一是冒泡排序进行一次交换代表消去一个逆序对。输入的v代表要消去的逆序对的个数。

二是由于贪心思想,我们优先选取字典序低的字母。

三是我看用例猜测,bbaa、ccbbaa,这种连续两个的应该是要尽量多【当然看了下别人好像三个也行,猜测光荣阵亡。但这点可以看看能不能完善】

在以上的思路基础下,

于是认为,结果字符串应该是类似于那样的结构,再加上fghj这种之后的字母排成的前缀。

例如输入为100时的字符串

jihgfeeddccbbaa

观察字符串,可得所需逆序对数量v=前缀逆序对数+后缀逆序对数+后缀字母数量*前缀字母数量。

其中前缀指的是前面的乱七八糟部分,后缀指的是成对出现的数字。

而由于这样的字符串其实由后缀决定,所以我选择枚举后缀所拥有的字母种类数,最终取得最小值。

所以我们首先任务就是以字母种数创造后缀字符串数组,记录每种字母种类数的值。【仔细想,这里似乎不需要创建数组,之后实时算不知道行不行?】

对于后缀的字符串,我选用了抽象的定义和创造方法。

以”aa“、”bbaa“这种为一个doubleNode,包含它内部的逆序对数和它所拥有的字母数。并且doubleNode数列内部满足递推公式。

这里其实可以根据n的数据范围优化array的大小。这地方还没写。

typedef struct doubleNode{
	int eleNum;
	int value;
}doubleNode;
doubleNode* CountArray(int n){
	doubleNode* array=(doubleNode*)malloc(sizeof(doubleNode)*50);
	array[0].eleNum=2;
	array[0].value=0;
	for(int i=1;i<50;i++){
		array[i].value=array[i-1].value+array[i-1].eleNum*2;
		array[i].eleNum=array[i-1].eleNum+2;
	}
	return array;
}

 接下来我们再写一个函数,表示前缀字母位数为n时逆序对最多有多少

int CountNixu(int n){
	return (n*(n-1))/2;
}

接下来是主体函数【因为是自用,所以变量名取得乱了】。在主体函数中,我们需要枚举后缀每个字母种数,并通过公式计算。以minAlpha变量表示字母数,index表示选到的后缀数组下标,moreNum表示选到的前缀字母个数。

再然后,根据上述三个变量信息组合字符串,return。

这个过程有什么问题呢?我默认了每个前缀字符串都取到了它最大的逆序对数。这一点实际上应该不大可能。针对此,我还真不知道要咋办。我的想法是,除了记录moreNum外,还要记录对应所需的逆序对数,再写一个根据逆序对数计算出字符串排列的函数。我之后有机会试试看。

char* ReturnGoal(int v){
	doubleNode* array=CountArray(v);
	int minAlpha=INF;
	int index=0;
	int moreNum=0;
	for(int i=0;i<50;i++){
		if(array[i].value>v)	break;
		int left=v-array[i].value;
		for(int j=0;j<50;j++){
			int sum=array[i].eleNum*j+CountNixu(j);
			if(sum>=left){
				int eleSum=array[i].eleNum+j;
				if(eleSum<=minAlpha){
					minAlpha=eleSum;
					index=i;
					moreNum=j;
				}
				break;
			}
		}
	}
	char* result=(char*)malloc(sizeof(char)*50);
	int count=0;
	for(int i=index+moreNum;i>index;i--){
		result[count++]=(char)(i+'a');
	}
	for(int i=index;i>=0;i--){
		result[count++]=(char)(i+'a');
		result[count++]=(char)(i+'a');
		//TODO
	}
	result[count]='\0';
	return result;
}

因而算是bug众多。但是毕竟是我为数不多思考比较多的题目www,所以就放在这里了。早睡,保命要紧。

完整代码如下:

#include 
#include 
#include 
#include 
#define INF 100000
typedef struct doubleNode{
	int eleNum;
	int value;
}doubleNode;
doubleNode* CountArray(int n){
	doubleNode* array=(doubleNode*)malloc(sizeof(doubleNode)*50);
	array[0].eleNum=2;
	array[0].value=0;
	for(int i=1;i<50;i++){
		array[i].value=array[i-1].value+array[i-1].eleNum*2;
		array[i].eleNum=array[i-1].eleNum+2;
	}
	return array;
}
//计算逆序数为n的最少位数 
int CountNixu(int n){
	return (n*(n-1))/2;
}

char* ReturnGoal(int v){
	doubleNode* array=CountArray(v);
	int minAlpha=INF;
	int index=0;
	int moreNum=0;
	for(int i=0;i<50;i++){
		if(array[i].value>v)	break;
		int left=v-array[i].value;
		for(int j=0;j<50;j++){
			int sum=array[i].eleNum*j+CountNixu(j);
			if(sum>=left){
				int eleSum=array[i].eleNum+j;
				if(eleSum<=minAlpha){
					minAlpha=eleSum;
					index=i;
					moreNum=j;
				}
				break;
			}
		}
	}
	char* result=(char*)malloc(sizeof(char)*50);
	int count=0;
	for(int i=index+moreNum;i>index;i--){
		result[count++]=(char)(i+'a');
	}
	for(int i=index;i>=0;i--){
		result[count++]=(char)(i+'a');
		result[count++]=(char)(i+'a');
		//TODO
	}
	result[count]='\0';
	return result;
}

int main(){
	printf("%s",ReturnGoal(100));
}

你可能感兴趣的:(数据结构与算法,蓝桥杯,排序算法,职场和发展)