您的位置:首页 > 其它

把数组排成最小的数

2015-09-30 19:05 232 查看
题目:输入一个正整数组,把数组里所有数字拼接起来排成一个数,打印能拼接出的所有数字中最小的一个。

例子:输入数组{3,32,321},则打印出这3个数字能排成的最小数字321323。

方法1:n个数字求 n! 个排列,找出最小值。

方法2:把数字转换成字符串,变成字符串数组排序,重新编写一些排序规则。

const int g_MaxNumberLength = 10;

char* g_StrCombine1 = new char[g_MaxNumberLength * 2 + 1];
char* g_StrCombine2 = new char[g_MaxNumberLength * 2 + 1];

void PrintMinNumber(int* numbers, int length){
if (numbers == NULL || length <= 0){
return;
}

char** strNumbers = (char**)(new int[length]);
for (int i = 0; i < length; ++i){
strNumbers[i] = new char[g_MaxNumberLength + 1];
sprintf(strNumbers[i], "%d", numbers[i]);
}

qsort(strNumbers, length, sizeof(char*), compare);

for (int i = 0; i < length; ++i){
printf("%s", strNumbers[i]);
}
printf("\n");

for (int i = 0; i < length; ++i){
delete[] strNumbers[i];
}
delete[] strNumbers;
}

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);
}


正确性证明

首先证明比较规则满足自反性,对称性和传递性。

自反性:显然有 aa=aa

对称性:如果a小于b,则 ab<ba,所以ba>ab,因此b大于a

传递性:如果a小于b,则 ab<ba。假设a和b用十进制表示时分别有1位和m位,于是ab=a×10m+b,ba=b×10+a。ab<ba→a×10m+b<b×10+a→a×10m−a<b×10−b→a(10m−1)<b(10−1)→a/(10−1)<b/(10m−1)

同时如果b小于c,则bc<cb。假设c用十进制表示是有n位,和前面的证明过程一样,可以得到b/(10m−1)<c/(10n−1)。

因此可得b/(10m−1)<c/(10n−1)→a/(10−1)<c/(10n−1)→a(10n−1)<c(10−1)→a×10n+c<c+10+a→<c×10+a→ac<ca→a小于c

其次证明用这种比较规则把数组排序之后,把数组中的所有数字拼接起来得到的数字的确是最小的。使用反证法。把n个数按前面的排序规则排序之后,表示为A1A2A3...An。假设这样拼接出来的数字不是最小的,即至少存在两个x和y(0<x<y<n),交换第x个数和第y个数后,A1A2...Ay...Ax...An<A1A2...Ax...Ay...An。

由于A1A2...Ax...Ay...An是按照前面的规则排好的序列,所以有Ax小于Ax+1小于Ax+2小于…小于Ay−2小于Ay−1小于Ay。

由于Ay−1小于Ay,所以Ay−1Ay<AyAy−1 。我们在序列A1A2...Ax...Ay−1Ay...An 中交换Ay−1 和 Ay,有A1A2...Ax...Ay−1Ay...An<A1A2...Ax...AyAy−1...An。我们就这样一直把Ay和前面的数字交换,知道和Ax交换为止。于是就有A1A2...Ax...Ay−1Ay...An<A1A2...Ax...AyAy−1...An<A1A2...Ax...AyAy−2Ay−1...An<...<A1A2...AyAx...Ay−2Ay−1...An。

同理由于Ax小于Ax+1,所以AxAx+1<Ax+1Ax。我们在序列A1A2...AyAxAx+1...Ay−2Ay−1...An 中只交换Ax 和 Ax+1,有A1A2...AyAxAx+1...Ay−2Ay−1...An<A1A2...AyAx+1Ax...Ay−2Ay−1...An。我们接下来一直拿Ax和它后面的数字交换,直到和Ay−1交换为止。于是就有A1A2...AyAxAx+1...Ay−2Ay−1...An<A1A2...AyAx+1Ax...Ay−2Ay−1...An<...<A1A2...AyAx+1Ax+2...Ay−2Ay−1Ax...An。

所以A1A2...Ax...Ay...An<A1A2...Ay...Ax...An,这和我们的假设的A1A2...Ay...Ax...An<A1A2...Ax...Ay...An相矛盾。

所以假设不成立,我们的算法是正确的。

测试用例

功能测试(输入的数组中有多个数字,输入的数组中的数字有重复的数位,输入的数字只有一个数字)

特殊输入测试(数组的指针为NULL)
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  字符串 排序 数组