题目描述
给定一组非负整数,重新排列它们的顺序使之组成一个最大的整数。
练习地址
J45
实现
1、重写Collections.sort
class Solution {
public String largestNumber(int[] nums) {
StringBuilder str = new StringBuilder();
if (nums == null || nums.length == 0) return str.toString();
List<Integer> list = new ArrayList<>();
for (int n : nums) {
list.add(n);
}
Collections.sort(list, new Comparator<Integer>() {
@Override
public int compare(Integer s1, Integer s2) {
String o1 = s1 + "" + s2;
String o2 = s2 + "" + s1;
return o2.compareTo(o1);
}
});
if (list.get(0) == 0) return "0";
for (Integer l : list) {
str.append(l);
}
return str.toString();
}
}
2、解法:自定义排序
- 传递性证明:数学证明
- 思路:思路
- 示例2:
输入: [3,30,34,5,9] 输出: 9534330 - 想法
为了构建最大数字,我们希望越高位的数字越大越好。 - 算法
– 首先,我们将每个整数变成字符串。然后进行排序。
– 如果仅按降序排序,有相同的开头数字的时候会出现问题。比方说,样例 2 按降序排序得到的数字是 95343303,然而交换 33 和 3030 的位置可以得到正确答案 9534330。因此,每一对数在排序的比较过程中,我们比较两种连接顺序哪一种更好。我们可以证明这样的做法是正确的: - 假设(不是一般性),某一对整数 aa 和 bb ,我们的比较结果是 aa 应该在 bb 前面,这意味着 aa⌢b>b⌢a ,其中⌢ 表示连接。如果排序结果是错的,说明存在一个 cc , bb 在 cc 前面且 cc 在 aa 的前面。这产生了矛盾,因为 a⌢b>b⌢a 和 b⌢c>c⌢b 意味着 a⌢c>c⌢a 。换言之,我们的自定义比较方法保证了传递性,所以这样子排序是对的。
- 一旦数组排好了序,最“重要”的数字会在最前面。有一个需要注意的情况是如果数组只包含 0 ,我们直接返回结果 00 即可。否则,我们用排好序的数组形成一个字符串并返回。
- 复杂度分析
– 时间复杂度:O(nlgn)
尽管我们在比较函数中做了一些额外的工作,但是这只是一个常数因子。所以总的时间复杂度是由排序决定的,在 Python 和 Java 中都是 O(nlgn)O(nlgn) 。
– 空间复杂度:O(n)
这里,我们使用了 O(n)O(n) 的额外空间去保存 nums 的副本。尽管我们就地进行了一些额外的工作,但最后返回的数组需要 O(n)O(n) 的空间。因此,需要的额外空间与 nums 大小成线性关系。
class Solution {
public String largestNumber(int[] nums) {
// int数组转string数组
String[] strs = new String[nums.length];
for (int i = 0; i < nums.length; i++) {
strs[i] = String.valueOf(nums[i]);
}
// 重写排序
Arrays.sort(strs, new LNComparator());
// 数组最大值为0,则返回0
if (strs[0].equals("0")) return "0";
// 获取最大的字符串
String res = new String();
for (String s : strs) {
res += s;
}
return res;
}
private class LNComparator implements Comparator<String> {
@Override
public int compare(String s1, String s2) {
String o1 = s1 + s2;
String o2 = s2 + s1;
return o2.compareTo(o1); // o2>o1 ,返回 1
}
}