剑指 Offer 45. 把数组排成最小的数

27 篇文章 0 订阅
26 篇文章 0 订阅

力扣-剑指 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();
    }
}
 

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值