68.把数组排成最小的数(数组、算法)。

题目:输入一个正整数数组,将它们连接起来排成一个数,输出能排出的所有数字中最小的一个。

例如输入数组{32, 321},则输出这两个能排成的最小数字 32132。

请给出解决问题的算法,并证明该算法。

 

思路:首先,肯定要考虑溢出问题。开始想用字符串,后来改为了用list。思路是先把第一个数字放入list,然后依次把后面的数字插入到合适的位置。

关键问题就是如何判断两个数字哪一个在前面。

①对于 353 、412这样的情况,肯定是第一个数字小的在前面

②遇到数字相同的就比较下一个数字

③那像 3、 32 这样的情况,两个数字前面相同后面不一样长的  把长的数字去掉相同的部分再跟短的数字比 

如 3 、3332

3、332

3、32

3、2 后面的数字放前面

再如 321321321、321

321321、321

321、321 相等 哪个放在前面都一样

 

为了获取数字的每一位方便,有定义了一个结构,存放每个数字各个位上的数,以及位数的大小。整体代码如下:



/*
68.把数组排成最小的数(数组、算法)。
题目:输入一个正整数数组,将它们连接起来排成一个数,输出能排出的所有数字中最小的一个。
例如输入数组{32, 321},则输出这两个能排成的最小数字 32132。
请给出解决问题的算法,并证明该算法。
start to code = 18:42
end time = 19:47
*/

#include <iostream>
#include <list>
using namespace std;

typedef struct SeperateNum
{
int num[30]; //在前面的是低位
int len;
}SeperateNum;

SeperateNum getSeperateNum(int n)
{
SeperateNum s;
s.len = 0;
int t = n;
while(t != 0)
{
s.num[s.len++] = t % 10;
t = t / 10;
}
if (s.len == 0) //只有一个数字0的情况
{
s.num[0] = 0;
s.len = 1;
}
return s;
}

bool isBefore(SeperateNum a, int na, SeperateNum b, int nb) //a 是否应该放在 b前面 n为当前判断第几个数字
{
if (b.len - nb < 0 && a.len - na < 0) //两个数字相等 或者一个数字是另一个数字复制了 n遍 321 321321321哪个放前面都一样
{
return true;
}
else if (b.len - nb < 0 && a.len - na >= 0) //b数字比较短 且b与a的前面都相等
{
return isBefore(a, na, b, 1);
}
else if(b.len - nb >= 0 && a.len - na < 0) //a数字比较短
{
return isBefore(a, 1, b, nb);
}

if (a.num[a.len - na] > b.num[b.len - nb])
{
return false;
}
else if (a.num[a.len - na] < b.num[b.len - nb])
{
return true;
}
else //本位数字相等判断下一位
{
return isBefore(a, na + 1, b, nb + 1);
}
}

void getMinNum(int * in, int len) //输入数组 和 长度
{
list<SeperateNum> lminNum;
list<SeperateNum>::iterator it;
SeperateNum temp = getSeperateNum(in[0]);
bool isInsert = false;

lminNum.push_back(temp);
for (int i = 1; i < len; i++)
{
isInsert = false;
temp = getSeperateNum(in[i]);
for(it = lminNum.begin(); it != lminNum.end(); it++)
{
if (isBefore(temp, 1, *it, 1)) //需要插入
{
lminNum.insert(it, temp);
isInsert = true;
break;
}
}
if (isInsert == false) //没有在中间插入 插在最后面
{
lminNum.push_back(temp);
}
}

cout << "组合成的最小数字是:";
for(it = lminNum.begin(); it != lminNum.end(); it++) //输出最小的数字 注意判断结束要用 ‘ != ’ 不能用‘ < ’
{
for(int i = it->len - 1; i >= 0; i--)
{
cout<< it->num[i];
}
}
cout<< endl;
}

int main()
{
int a[5] = {321, 321321325, 3, 32};
getMinNum(a, 4);

return 0;
}


查到了一个讲C++不错的网址​​http://www.cplusplus.com/reference/list/list/insert/​

整整写了100多行,用到了自定义结构、STL、递归各种复杂的东西。用了1个多小时,还不包括思考的时间。

 

在网上找答案,发现人家的答案都好简洁啊。

方法相当的简单,我怎么就没有想到。 就是把两个数a、b 正反都拼一下 ab、ba 比较一下那个数小就行了。

代码里面直接用了strcmp来做这个。



#include <iostream>
#include <string.h>
using namespace std;

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

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

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++)
cout<<strNumbers[i];
cout<<endl;

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

delete[] strNumbers;

}

void main()
{
int Num;
cin>>Num;
int *numbers=new int[Num];
for(int i=0; i<Num; i++)
cin>>numbers[i];

PrintMinNumber(numbers, Num);
getchar();
}


 

另一个实现:



#include <iostream>
#include <string>
#include <sstream>
#include <algorithm>
using namespace std;

bool compare(const string& str1, const string &str2)
{
string s1=str1+str2;
string s2=str2+str1;
return s1<s2;
}

void ComArrayMin(int *pArray, int num)
{
int i;
string *pStrArray=new string[num];

for(i=0; i<num; i++)
{
stringstream stream;
stream<<pArray[i];
stream>>pStrArray[i];
}

sort(pStrArray, pStrArray+num, compare);

for(i=0; i<num; i++)
cout<<pStrArray[i];

cout<<endl;

delete[] pStrArray;

}

void main()
{
int Num;
cin>>Num;
int *pArray=new int[Num];

for(int i=0; i<Num; i++)
cin>>pArray[i];

ComArrayMin(pArray, Num);

}