
//面试题45.把数组排成最小的数
//题目:
/*
输入一个正整数数组,把数组里所有数字拼接起来,排成一个数,打印能拼接处的所有数字中最小的一个。
例如,输入数组{3,32,321},则打印出这3个数字能排成的最小数字321323.
*/
/*
思路:
首先对于这种题目,单独一个int类型的数字不会溢出,但是几个int类型拼接起来之后,可能会导致用int类型表示溢出。
因此这种问题属于大数问题,对于大数问题,我们一般的解决思路是通过将数字转换为字符串。因为拼接之后的所有数字的位数是一样的,
因此我们可以通过字符串大小的比较规则进行比较即可。(字符串大小的比较规则:字符串对应的ASCII码)
暴力法:
直接将数组中所有数字进行排列组合,对于一个长度为n的数组,其排列组合的种类有n!中,然后分别进行比较。
因此时间复杂度是O(n!)
优化方法:
1.为解决大数问题,将数组中的整型数字转化为字符串
2.比较两两个数字之间的先后顺序,谁排在前面更小,从而对数组进行排序
3.建立自己的排序规则(对于整型数组{m,n},如果字符串 mn < nm,那么我们定义m < n;如果字符串 mn > nm,那么我们定义m > n;如果字符串 mn = nm,那么我们定义m = n;)
4.两个数字先后顺序的比较方法:两个数字连接,比较两种连接方式得到的字符串哪个大。
*/
#pragma warning(disable : 4996)
#include<iostream>
#include<string>
#include<algorithm>
#include"cstdio"
int compare(const void*strNumber1, const void*strNumber2);
//int型整数用十进制表示最多只有10位(int型占4个字节,每个字节对应8位二进制数,最大值的位数位2^31,一共有10位)
const int g_MaxNumberLength = 10;
//定义两两字符串拼接之后,字符串数组的长度 = 每个整型十进制数对应的最长位数(10) * 2(两个) + 1(“0”字符串结束符)
char*g_StrCombine1 = new char[g_MaxNumberLength * 2 + 1];
char*g_StrCombine2 = new char[g_MaxNumberLength * 2 + 1];
void PrintMinNumber(const int*numbers, int length)
{
if (numbers == nullptr || length <= 0)
return;
//===================将整型数组转化为字符串数组=====================================
char**StrNumbers = (char**)(new int[length]);//初始化一个字符串数组,其中的元素也是字符串,也相当于一个数组,所以要用指针的指针
for (int i = 0; i < length; ++i)
{
StrNumbers[i] = new char[g_MaxNumberLength + 1];//将一个整型数字的十进制表示转换为字符串,除去十进制位数10,要加上一位结束符"0";
//初始化字符串数组的每个元素(每个元素也是一个字符串,也相当于一个数字组)
/*
函数原型:int sprintf(char *buffer, const char *format, [argument]...)
参数:
(1)buffer:是char类型的指针,指向写入的字符串指针;
(2)format:格式化字符串,即在程序中想要的格式;
(3)argument:可选参数,可以为任意类型的数据;
*/
sprintf(StrNumbers[i], "%d", numbers[i]);
}
//=======================将字符串数组进行升序排列================================
/*
void qsort(
void *base,
size_t nmemb,
size_t size,
int (*compar)(const void *, const void *)
);
函数功能:qsort()函数的功能是对数组进行排序,数组有nmemb个元素,每个元素大小为size。
参数base - base指向数组的起始地址,通常该位置传入的是一个数组名
参数nmemb - nmemb表示该数组的元素个数
参数size - size表示该数组中每个元素的大小(字节数)
参数(*compar)(const void *, const void *) - 此为指向比较函数的函数指针,决定了排序的顺序。
如果compar返回值小于0(< 0),降序排列
如果compar返回值等于0(= 0),顺序不确定
如果compar返回值大于0(> 0),升序排列
*/
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;
}
//如果[StrNumber1][StrNumber2] > [StrNumber2][StrNumber1],返回值大于0
//如果[StrNumber1][StrNumber2] < [StrNumber2][StrNumber1],返回值小于0
//如果[StrNumber1][StrNumber2] = [StrNumber2][StrNumber1],返回值等于0
int compare(const void*strNumber1,const void* strNumber2)
{
//[StrNumber1][StrNumber2]
//拼接字符串,通过STL中的strcpy(目标数组,要复制的字符串)
strcpy(g_StrCombine1, *(char**)strNumber1);
strcpy(g_StrCombine1, *(char**)strNumber2);
//[StrNumber2][StrNumber1]
strcpy(g_StrCombine2, *(char**)strNumber2);
strcpy(g_StrCombine2, *(char**)strNumber1);
return strcmp(g_StrCombine1, g_StrCombine2); //字符串比较函数strcmp(字符串1,字符串2),如果1 > 2,则返回值大于0;如果1 < 2,则返回值小于0;
}
//==========================================测试代码==============================
void Test(const char*testName, int*numbers, int length, const char*expectedResult)
{
if (testName != nullptr)
printf("%s begins:n", testName);
if (expectedResult != nullptr)
printf("Expected result is: t%sn", expectedResult);
printf("Actual result is:t");
PrintMinNumber(numbers, length);
printf("n");
}
void Test01()
{
int numbers[] = {3,5,1,4,2};
Test("Test01", numbers, sizeof(numbers) / sizeof(int), "12345");
}
void Test02()
{
int numbers[] = { 3,32,321 };
Test("Test02", numbers, sizeof(numbers) / sizeof(int), "321323");
}
int main()
{
Test01();
//Test02();
system("pause");
return 0;
}