题目:输入一个正整数组,将它们连接起来排成一个数,输出所能排出的所有数字中最小的一个。
例如输入数组{32,321},则输出这两个能排成的最小数字32132.
分析:这是一道非降排序问题,比较规则如下:
1、如果a,b位数相等,如12与31,则可直接比较大小。12<31,排序后结果为1231。
2、如果a,b位数不等。考虑如下三种情况:
a、31与312。大小为31>312,排序结果为31231
b、31与313。大小为31=313,排序结果为31313或者31331
c、31与314。大小为31<314,排序结果为31314
由上可以得知,a与b位数不等的时候,假如a为位数少,则为了对齐比较,补齐a后面缺少位数,用a的高位循环填充。然后比较a与b的大小关系。如31与31315比较,31位数小,则用31的高位循环补齐,为31313,然后比较31313与31315。大小为31313<31315,结果为3131315。对于b来说,如果31=313,那么再比较31与13的大小。
3、对于两个数已经说明结果,对于数组多于两个数时,可以采用数学归纳法来证明非降排序的正确性。
C/C++源码:
#include <iostream> #include <cstring> #include <cstdlib> using namespace std; const int N = 128; int comp(const void* a, const void* b){ char d1[N], d2[N]; //translate num to string sprintf(d1,"%d", *(int*)a); sprintf(d2,"%d", *(int*)b); int l1,l2,l; l1 = strlen(d1); l2 = strlen(d2); l = l1 > l2 ? l1 : l2; //to align two string for(int i=l1, j=0;i<l;i++){ d1[i] = d1[j]; j = (j+1)%l1; } d1[l]='/0'; for(int i=l2, j=0;i<l;i++){ d2[i] = d2[j]; j = (j+1)%l2; } d2[l]='/0'; if(strcmp(d1,d2)!=0) return strcmp(d1,d2); else{ if(l>l1){ d1[l1]='/0'; return -strcmp(d1,d2+l-l1); } else{ d2[l2]='/0'; return -strcmp(d1+l-l2,d2); } } } int main() { int A[]={3,2,1,31,313}; int num = sizeof(A)/sizeof(int); qsort(A,num,sizeof(int),comp); for(int i=0;i<num;i++) cout << A[i]; cout << endl; return 0; }