一、题目描述
题目大意:给定一个nums数组由一些非负整数组成,现需要将他们进行排列并拼接,每个数不可拆分,使得最后的结果最大,返回值需要是string类型,否则可能会溢出
注意审题:由一些非负整数组成,因此不必考虑负数的情况
二、算法一(排序)
解题思路
- 要使得拼接出的数尽可能的大,一种直观的想法就是令拼接出的数高位尽可能的大,这样整体就更大。对于两个数a、b,要求得最大值,直接比较两者拼接后的大小即可,因此我们可以定义一种比较大小的规则,即若 ab < ba ,则数b小于数a,应该排在数a之前,其中 ab = a * 10^count(b) + b (count(b)为b的位数)
- 当元素个数大于2时,我们只要证明了这种比较规则是满足传递性,就可以确定两个元素在排序后的相对位置关系,当确定了所有数的相对位置关系之后,整个数组拼接成的序列就是最终的结果
- 当一个数a排在数b使得结果更优时,我们记作 a#b ,要证明比较规则具有传递性,即证明 a#b 且 b#c 时,满足 a#c,证明如下:
由 a#b 且 b#c 可知:
- a * 10^count(b) + b >= b * 10^count(a) + a
- b * 10^count(c) + c >= c * 10^count(b) + b
整理得: - a * (10^count(b) - 1) >= b * (10^count(a) - 1)
- b * (10^count(c) - 1) >= c * (10^count(b) - 1)
由于均为非负整数,故将两式相乘得:
a * (10^count(c) - 1) * b * (10^count(b) - 1) >= c * (10^count(a) - 1) * b * (10^count(b) - 1)
为了证明 a#c,我们对b进行分类讨论:
(1) b = 0 时:
- 10^count(b) = 1,带入得等式两边都为0,此时满足a#c
(2) b > 0 时:
- b * (10^count(b) - 1) > 0,故等式两边同时除以b * (10^count(b) - 1)
- 得 a * 10^count(c) - a >= c * 10^count(a) - c,移项得 a * 10^count(c) + c >= c * 10^count(a) + a,满足 a#c
故得证排序规则具有传递性
代码实现(C++11)
class Solution {
public:
string solve(vector<int>& nums) {
// 为防止拼接后溢出
using LL = long long;
// 求非负整数x的数位
auto count = [](int x) -> int {
if(x == 0) return 1;
int cnt = 0;
while(x) {
++cnt;
x /= 10;
}
return cnt;
};
// 求10的k次幂
auto qmi = [](int k) -> int {
int ans = 1, a = 10;
while(k) {
if(k & 1) ans *= a;
a *= a;
k >>= 1;
}
return ans;
};
// 自定义排序
sort(nums.begin(), nums.end(), [=](const int &a, const int &b){
return (LL)b * qmi(count(a)) + a < (LL)a * qmi(count(b)) + b;
});
// 拼接整个字符串
string ans;
for(auto &num : nums) {
ans += to_string(num);
}
// 去除前导零
reverse(ans.begin(), ans.end());
while(ans.size() > 1 && ans.back() == '0') {
ans.pop_back();
}
reverse(ans.begin(), ans.end());
return ans;
}
}; 时间复杂度:,n为元素个数,时间复杂度取决于排序,使用快速排序,进行了
次比较,由于数据每个数都是小于
的非负整数,故每次比较的时间可以看做很小的常数,故总的时间复杂度为
空间复杂度:,排序递归深度为
三、算法二(优先级队列)
类似地,利用以上的结论,我们自定义比较规则,不过这里用优先级队列(堆)来实现,先将所有元素入堆,根据自定义的比较规则,每次先出堆的元素优先级更高,即出堆元素与堆中任意数两两组合形成的最大数,出堆元素总在前半部分,故只要依次将元素出堆即可得到最终的结果序列
代码实现(C++11)
struct cmp {
// 为防止拼接后溢出
using LL = long long;
// 求非负整数x的数位
int count(int x) {
if(x == 0) return 1;
int cnt = 0;
while(x) {
++cnt;
x /= 10;
}
return cnt;
}
// 求10的k次幂
int qmi(int k) {
int ans = 1, a = 10;
while(k) {
if(k & 1) ans *= a;
a *= a;
k >>= 1;
}
return ans;
}
// 重载()运算符
bool operator()(const int& a, const int& b) noexcept {
return (LL)b * qmi(count(a)) + a > (LL)a * qmi(count(b)) + b;
}
};
class Solution {
public:
string solve(vector<int>& nums) {
priority_queue<int, vector<int>, cmp> hp(nums.begin(), nums.end());
// 拼接整个字符串
string ans;
while(hp.size()) {
ans += to_string(hp.top());
hp.pop();
}
// 去除前导零
reverse(ans.begin(), ans.end());
while(ans.size() > 1 && ans.back() == '0') {
ans.pop_back();
}
reverse(ans.begin(), ans.end());
return ans;
}
}; 时间复杂度:,n为元素个数,堆的每次插入操作时间复杂度为
,共总时间复杂度为
空间复杂度:,堆使用的空间是
的

京公网安备 11010502036488号