力扣-剑指 Offer 45. 把数组排成最小的数
剑指 Offer 45. 把数组排成最小的数
题目描述
输入一个非负整数数组,把数组里所有数字拼接起来排成一个数,打印能拼接出的所有数字中最小的一个。
示例 1:
输入: [10,2]
输出: “102”
示例 2:
输入: [3,30,34,5,9]
输出: “3033459”
提示:
0 < nums.length <= 100
说明:
输出结果可能非常大,所以你需要返回一个字符串而不是整数
拼接起来的数字可能会有前导 0,最后结果不需要去掉前导 0
来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/ba-shu-zu-pai-cheng-zui-xiao-de-shu-lcof
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
解题思路:
自己的思路如下:
首先按照每个数的最高位进行排序,最高位相同的数字按照第二位排序,依次内推
上述思路优化:
位数最多的数字是最大的数字;
找到位数最多的数字,记位数最大数量为M,其余位数不到M的,也当做位数为M,不足的位数用0来填凑,不影响最终结果
思路再次优化:
用0在右边填充位数不到M的,会出现一个问题:当比较的两个非0数字都相同的情况下,判断比较麻烦。于是考虑直接把比较的两个数分别放在第一个位置拼接起来,然后依次比较每一位,遇到小的数直接返回比较结果。这样思路简单,没有很多复杂的判断。
具体思路如下:
将每个数放到集合中,如果遇到0,则不放入,单独统计0的个数;
进行排序:自定义排序规则:将两个数A、B拼接起来,有两种拼接方案:AB和BA,逐位比较数AB和数BA,如果遇到第一位较小的数,直接返回比较结果。
我们在比较两个long类型数的时候,可以通过Collections工具类的sort方法,传入自定义的比较器Comparator,然后自己实现比较器中的compare方法,在compare方法中逐位比较拼接后的两个数。也可以直接调用Long类型实现的compareTo方法,直接就能比较两个long类型个的数字。tempLongNum1.compareTo(tempLongNum2)
为了避免出现int最大的值,防止精度损失,我们用Long来表示拼接后的两个数,这里也涉及到了集合中long值的比较问题,我会单独写一篇文章来分享我关于这部分的心得。
代码如下:
class Solution {
//自己的思路
public String minNumber(int[] nums) {
StringBuilder res = new StringBuilder();
if (nums == null || nums.length <= 0) {
return res.toString();
}
List<Integer> list = new ArrayList<>();
int zeroNum = 0;
for (int i = 0; i < nums.length; i++) {
if (nums[i] == 0) {
zeroNum++;
continue;
}
list.add(nums[i]);
}
if (list.size() > 0) {
int maxNum = Collections.max(list);
int M = (int)Math.log10(maxNum) + 1;//最大数的最大位数
Collections.sort(list, new Comparator<Integer>(){
public int compare(Integer o1, Integer o2) {
int M1 = (int)Math.log10(o1) + 1;
//Long longNum1 = (long)Math.pow(10, M - M1) * o1;
int M2 = (int)Math.log10(o2) + 1;
//Long longNum2 = (long)Math.pow(10, M - M2) * o2;
/*if (longNum1 == longNum2) {//加上0之后值相等 位数多的在前面 从大到小排序
return o2 - o1;
}*/
//将两个数分别放在第一个位置进行比较
//o1o2和o2o1的组合方案逐位比较
//从高位到低位逐位比较 一旦某一个位置不一样 小的值先返回
int pos = M1 + M2;
Long tempLongNum1 = o1 * (int)Math.pow(10, M2) + (long)o2;//以o1开头
Long tempLongNum2 = o2 * (int)Math.pow(10, M1) + (long)o1;//以o2开头
if (tempLongNum1 == tempLongNum2) {//拼接值相等 不需要换位置
return o2 - o1;
}
/*while (pos > 0) {
int posVal1 = (int)(tempLongNum1 / (int)(Math.pow(10, pos - 1)));
int posVal2 = (int)(tempLongNum2 / (int)(Math.pow(10, pos - 1)));
System.out.println("posVal1: " + posVal1 + " posVal2: " + posVal2);
if (posVal1 > posVal2) {
return posVal1 - posVal2;
}
pos--;
}*/
//在较小的位数上数值都相同,比较
return tempLongNum1.compareTo(tempLongNum2);
}
});
}
for (int i = 0; i < zeroNum; i++) {
res.append(0);
}
for (Integer num : list) {
res.append(num);
}
return res.toString();
}
}