把数组排成最小的数
2015-09-30 19:05
232 查看
题目:输入一个正整数组,把数组里所有数字拼接起来排成一个数,打印能拼接出的所有数字中最小的一个。
例子:输入数组{3,32,321},则打印出这3个数字能排成的最小数字321323。
方法1:n个数字求 n! 个排列,找出最小值。
方法2:把数字转换成字符串,变成字符串数组排序,重新编写一些排序规则。
正确性证明:
首先证明比较规则满足自反性,对称性和传递性。
自反性:显然有 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)
例子:输入数组{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)
相关文章推荐
- 数据库链接字符串查询网站
- 文件遍历排序函数
- Flex字符串比较 还有Flex字符串操作
- ruby 数组使用教程
- Ruby中的数组和散列表的使用详解
- C#实现AddRange为数组添加多个元素的方法
- C#选择排序法实例分析
- C#动态调整数组大小的方法
- Ruby中创建字符串的一些技巧小结
- ASP下经常用的字符串等函数参考资料
- 将字符串小写转大写并延时输出的批处理代码
- 将字符串转换成System.Drawing.Color类型的方法
- C#插入法排序算法实例分析
- 详解Lua中的数组概念知识
- Lua源码中字符串类型的实现
- Lua性能优化技巧(四):关于字符串
- 字符串聚合函数(去除重复值)
- C#实现Datatable排序的方法
- Perl中的列表和数组学习笔记
- Ruby中的字符串编写示例