题目:输入一个正整数数组,将它们连接起来排成一个数,输出能排出的所有数字中最小的一个。例如输入数组{32, 321},则输出这两个能排成的最小数字32132。请给出解决问题的算法,并证明该算法。
分析:这是09年6月份百度新鲜出炉的一道面试题,从这道题我们可以看出百度对应聘者在算法方面有很高的要求。
这道题其实是希望我们能找到一个排序规则,根据这个规则排出来的数组能排成一个最小的数字。要确定排序规则,就得比较两个数字,也就是给出两个数字m和n,我们需要确定一个规则m和n哪个更大,而不是仅仅只是比较这两个数字的数值哪个更大。
根据题目的要求,两个数字m
和n排成的数字mn和nm,如果mn<nm,那么我们应该输出mn,也就是m应该排在n的前面,也就是m小于n;反之,如果nm<mn,n小于m。如果mn==mn,m等于n。
接下来我们考虑怎么去拼接数字,即给出数字m和n,怎么得到数字mn和nm并比较它们的大小。直接用数值去计算不难办到,但需要考虑到的一个潜在问题是m和n都在int能表达的范围内,但把它们拼起来的数字mn和nm就不一定能用int表示了。所以我们需要解决大数问题。一个非常直观的方法就是把数字转换成字符串。
另外,由于把数字m和n拼接起来得到的mn和nm,它们所含有的数字的个数肯定是相同的。因此比较它们的大小只需要按照字符串大小的比较规则就可以了
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
const int g_MaxNumberLength=10;
char* g_StrCombine1=(char*)malloc((2*g_MaxNumberLength+1)*sizeof(char));
char* g_StrCombine2=(char*)malloc((2*g_MaxNumberLength+1)*sizeof(char));
//定义比较规则
int compare(const void* strNumber1,const void* strNumber2)
{
strcpy(g_StrCombine1,*(const char**)strNumber1);
strcat(g_StrCombine1,*(const char**)strNumber2);
strcpy(g_StrCombine2,*(const char**)strNumber2);
strcat(g_StrCombine2,*(const char**)strNumber1);
return strcmp(g_StrCombine1,g_StrCombine2);
}
void printMinNumber(int* numbers,int length)
{
if(numbers==NULL||length<=0)
return;
char** strNumbers=(char**)malloc(length*sizeof(int));
for(int i=0;i<length;++i)
{
strNumbers[i]=(char*)malloc((g_MaxNumberLength+1)*sizeof(char));
sprintf(strNumbers[i],"%d",numbers[i]);
}
qsort(strNumbers,length,sizeof(char*),compare);//库函数qsort排序
for(int i=0;i<length;++i)
printf("%s",strNumbers[i]);
printf("\n");
for(int i=0;i<length;i++)
free(strNumbers[i]);
free(strNumbers);
}
int main()
{
int* numbers;
int length;
scanf("%d",&length);
numbers=(int*)malloc(length*sizeof(int));
for(int i =0;i<length;i++)
scanf("%d",&numbers[i]);
printMinNumber(numbers,length);
return 0;
}
结果: