【剑指Offer-45】把数组排成最小的数
问题
输入一个非负整数数组,把数组里所有数字拼接起来排成一个数,打印能拼接出的所有数字中最小的一个。
说明:
- 输出结果可能非常大,所以你需要返回一个字符串而不是整数;
- 拼接起来的数字可能会有前导 0,最后结果不需要去掉前导 0。
示例
输入: [3,30,34,5,9]
输出: "3033459"
解答1:最小堆
class Solution {
public:
struct cmp {
bool operator() (string& s1, string& s2) {
return s1 + s2 > s2 + s1;
}
};
string minNumber(vector<int>& nums) {
string res;
priority_queue<string, vector<string>, cmp> p;
for (int i : nums) p.push(to_string(i));
while (!p.empty()) {
res += p.top();
p.pop();
}
return res;
}
};
解答2:库函数sort
class Solution {
public:
string minNumber(vector<int>& nums) {
string res;
vector<string> strs;
for (auto i : nums) strs.push_back(to_string(i));
sort(strs.begin(), strs.end(), [](const auto& s1, const auto& s2) {
return s1 + s2 < s2 + s1;
});
for (auto s : strs) res += s;
return res;
}
};
重点思路
本题的要点是对输入的数组按照题目要求自定义排序。自定义排序只需要记住,当return为true时,你期望的是s1在s2的前面。该自定义条件直观上很容易想到,因为题目要求的就是字符串组成的值最小,那么我们就需要让能组成较小值的元素排在最前面,自定义排序实现了这个功能。
这里还需要注意的是,需要证明xy < yx,yz < zy时,xz < zx
,即传递性。这里引用一下题解里的证明:
字符串 xy < yx , yz < zy ,需证明 xz < zx 一定成立。
设十进制数 x, y, z 分别有 a, b, c 位,则有:
(左边是字符串拼接,右边是十进制数计算,两者等价)
xy = x * 10^b + y
yx = y * 10^a + x
则 xy < yx 可转化为:
x * 10^b + y < y * 10^a + x
x (10^b - 1) < y (10^a - 1)
x / (10^a - 1) < y / (10^b - 1) ①
同理, 可将 yz < zy 转化为:
y / (10^b - 1) < z / (10^c - 1) ②
将 ① ② 合并,整理得:
x / (10^a - 1) < y / (10^b - 1) < z / (10^c - 1)
x / (10^a - 1) < z / (10^c - 1)
x (10^c - 1) < z (10^a - 1)
x * 10^c + z < z * 10^a + x
∴ 可推出 xz < zx ,传递性证毕
解答3:自定义快速排序
class Solution {
public:
string minNumber(vector<int>& nums) {
string res;
vector<string> strs;
for (int i : nums) strs.push_back(to_string(i));
quickSort(strs, 0, strs.size() - 1);
for (string s : strs) res += s;
return res;
}
private:
void quickSort(vector<string>& strs, int start, int end) {
if (start >= end) return;
int left = start, right = end;
string pivot = strs[start];
while (left < right) {
while (left < right && strs[right] + pivot >= pivot + strs[right]) right--; // 自定义部分
while (left < right && strs[left] + pivot <= pivot + strs[left]) left++; // 自定义部分
swap(strs[left], strs[right]);
}
swap(strs[left], strs[start]);
quickSort(strs, start, left - 1);
quickSort(strs, left + 1, end);
}
};