Leetcode 179 Largest Number

Leetcode 179 Largest Number

题目

Given a list of non negative integers, arrange them such that they form the largest number.

Example 1:
Input: [10,2]
Output: “210”

Example 2:
Input: [3,30,34,5,9]
Output: “9534330”
Note: The result may be very large, so you need to return a string instead of an integer.

思路

考虑自定义一个comparator去比较大小,“大”的概念就是数字出现在答案的前面部分。
多写几个例子可以发现,例如12和1212,123和123123123这种循环的都是相等的,谁放前面都是同一个数,这就给了我们一个比较基本的想法,以长度短的为一个周期一位一位去比较。
例如34和345,把34看成34|5,5比3大所以345大,验证34534>34345,也可以看到大小差确实发生在5和3这位上;同理34和34|2,就是34大,验证34342>34234。
最复杂的是刚才比较下来是相等的,但其实不相等因为位数不同,举几个例子。

8308和830
8308 > 830 因为 8308830 > 8308308,我们发现产生差异的是8 > 3那位。

12和121
132 > 1321 因为1321321 > 1321132,产生差异的是3 > 1那位。

332和3323
3323 > 332,因为3323323 < 3323332,产生差异的是3 > 2那位。

334和3343
334 > 3343,因为3343343 > 3343334,产生差异的是4 > 3那位。

这时观察发现产生差异的是长度较短的数从左往右比较第i位和第i+1位的大小决定的,结合例子可以方便理解他们的大小和对应比较的位数的关系。

代码

class Solution {
    public String largestNumber(int[] nums) {
        Integer[] temp = Arrays.stream(nums)
            .boxed()
            .sorted(
            (o1, o2) -> {
            String s1 = Integer.toString(o1);
            String s2 = Integer.toString(o2);
            if (s1.length() == s2.length()) return Integer.compare(o1, o2);
            if (s1.length() < s2.length()) {
                for (int i = 0; i < s2.length(); i++) {
                    if (s1.charAt(i % s1.length()) < s2.charAt(i)) {
                        return -1;
                    } else if (s1.charAt(i % s1.length()) > s2.charAt(i)) {
                        return 1;
                    }
                }
                for (int i = 0; i < s1.length() - 1; i++) {
                    if (s1.charAt(i) > s1.charAt(i + 1)) {
                        return -1;
                    }
                }
                return 1;
            } else {
                for (int i = 0; i < s1.length(); i++) {
                    if (s1.charAt(i) < s2.charAt(i % s2.length())) {
                        return -1;
                    } else if (s1.charAt(i) > s2.charAt(i % s2.length())) {
                        return 1;
                    }
                }
                for (int i = 0; i < s2.length() - 1; i++) {
                    if (s2.charAt(i) > s2.charAt(i + 1)) {
                        return -1;
                    }
                }
                return -1;
            }
        })
        .toArray(Integer[]::new);
        StringBuilder sb = new StringBuilder();
        int i = temp.length - 1;
        while (i >= 0 && temp[i] == 0) {
            i--;
        }
        for (; i >= 0; i--) {
            sb.append(temp[i]);
        }
        return sb.toString().equals("") ? "0" : sb.toString();
    }
}

优化

代码中用到了转成Integer类后使用数组自带排序的方法,显然直接自己写一个mergeSort会更好。
查看Sample答案,还有一个很好的想法是比较的时候并不适用String而是计算出两个数a,b的位数,然后a10进行b的位数次+b和b10进行a的位数次+a两个数直接比较,参考代码如下。

class Solution {
    public String largestNumber(int[] nums) {
        sort(nums, 0, nums.length);

        // If the first element is 0, the result itself is 0
        if (nums[0] == 0) return "0";

        StringBuilder result = new StringBuilder();
        for (int num : nums) result.append(num);

        return result.toString();
    }

    // We can use string comparator
    // (b + a).compareTo(a + b)
    // However, concatenating strings and comparing takes more time
    // So, use the above logic but using number
    private boolean compare(int a, int b) {
        long aLong = a * 10, bLong = b * 10;
        int x = a, y = b;

        while ((x /= 10) > 0) bLong *= 10;
        while ((y /= 10) > 0) aLong *= 10;

        return (aLong + b) > (bLong + a);
    }        

    // The array is of primitive, so we cannot pass comparator
    // This is a compact version of merge sort
    private void sort(int[] nums, int l, int r) {
        if (l >= r - 1) return ;
        int m = l + (r - l) / 2;

        sort(nums, l, m);
        sort(nums, m, r);
        merge(nums, l, m, r);
    }

    private void merge(int[] nums, int l, int m, int r) {
        int[] aux = new int[r - l];

        for (int i = l, j = m, k = 0; i < m || j < r;) {
            if (i < m && (j == r || compare(nums[i], nums[j]))) aux[k++] = nums[i++];
            else if (j < r) aux[k++] = nums[j++];
        }

        for (int i = 0; l < r; ++i) nums[l++] = aux[i];
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值