程序员面试题精选100题(41)-把数组排成最小的数
以下文字摘自 http://zhedahht.blog.163.com/blog/static/25411174200952174133707/
题目:输入一个正整数数组,将它们连接起来排成一个数,输出能排出的所有数字中最小的一个。例如输入数组{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,它们所含有的数字的个数肯定是相同的。因此比较它们的大小只需要按照字符串大小的比较规则就可以了。
——————————————————————————————
代码实现其实并不需要向他实现的那么复杂。
其核心的代码是实现cmp函数。
代码如下
int front_cmp(const void *a,const void *b)
{
int first = *(int *)a;
int second = *(int *)b;
/*
while(first > 9)
first /= 10;
while(second > 9 )
second /= 10;
return first - second;
*/
static char pbuf1[21];
static char pbuf2[21];
sprintf(pbuf1,"%d%d",first,second);
sprintf(pbuf2,"%d%d",second,first);
return strcmp(pbuf1,pbuf2);
}
说明:1.static是为了避免多次栈中分配空间,分配21是由于max_int最大数只有10位数。
2.sprintf函数是替代atoi的一个比较通用的方案。
再通过快速排序,即可得到答案。输出数组里面的数(连续输出,不要有空格即可)
经过测试,结果正确可行。