输入一个正整数数组,将数组中各个数字连成一个数,输出所有可能的数字中最小的那个数。
举个栗子:
输入: 3,32,321
输出: 321323
最直观的做法是穷举所有排列所组成的数字,再从中找出最小的,该解法由于要穷举所有排列,所以复杂度至少为O(n!)。
有一种O(n*logn)的解法是,先对数组中数字按从小到大的顺序排序,再将数组中数字连接起来即为最小的数。
这里需要注意两点:
- 排序过程中,按递增顺序排列后得到的数字不一定是最小值。
比如,3、32、321连接起来是332321并不是最小值,而321323才是所要求的最小值。所以这里需要改变排序规则,新规则必须使得排序后数字连接起来是最小的,在该例中,新规则排序后结果应该为321、32、3.
新规则为:对于a,b两个数,将二者连接起来,若ab < ba,说明a在前b在后的排列所得到的数比较小。则认为a“小于”b,因此将a排在b前。(由于排序过程中会使用stl中的sort函数,因此时间复杂度为O(n*logn)) - 在将两个整数连接起来时,如果这两个整数比较大,则可能出现连接后数字超过整数范围的情况。因此考虑使用字符串来保存连接后数据。
代码为:
class Solution {
public:
string PrintMinNumber(vector<int> numbers) {
int n = numbers.size();
if (n < 1) {return "";}
if (n == 1) {return int2str(numbers[0]);}
string s = "";
sort(numbers.begin(),numbers.end(),mycompare);
for (auto num:numbers) {
s += int2str(num);
}
return s;
}
static bool mycompare(const int &a, const int &b) {
string s1 = int2str(a) + int2str(b);
string s2 = int2str(b) + int2str(a);
return (s1<s2);
}
static string int2str(int n) {
stringstream ss;
string str;
ss << n;
ss >> str;
return str;
}
};
解法二:
先将数组按从小到大排序,再遍历数组,按照“如果ab < ba,那么a排在b前”的规则,将数组中数字连接成一个数字,该数即为数组中数字所能排成的最小的数。
代码二:
class Solution {
public:
string PrintMinNumber(vector<int> numbers) {
int n = numbers.size();
if (n < 1) {return "";}
if (n == 1) {return int2str(numbers[0]);}
string s = "";
sort(numbers.begin(),numbers.end()); // !!
s += int2str(numbers[0]);
for(int i=1; i<n; ++i) {
string s1 = s + int2str(numbers[i]);
string s2 = int2str(numbers[i]) + s;
s = strcmp(s1.c_str(),s2.c_str()) > 0 ? s2 : s1;
}
return s;
}
string int2str(int n) { //?这里为什么不用static也可以?
stringstream ss;
string str;
ss << n;
ss >> str;
return str;
}
};
有个问题!
3、32、329 排成的最小数字应该是:323293
为什么这些代码输出的结果都是:323329 ??!!
而牛客网上以上两个代码却都可以ac,而其他网友的代码对于3、32、329也输出的是323329?