【Lintcode】184. Largest Number

题目地址:

https://www.lintcode.com/problem/largest-number/description

给定一个数组,要求将这些数全部拼接起来,问能拼出的最大数是多少。返回那个数的字符串形式即可。

首先,如果给定数字构成的两个字符串 s 1 s_1 s 2 s_2 ,那么很容易判断 s 1 + s 2 s_1+s_2 s 2 + s 1 s_2+s_1 形成的数字哪个更大。我们对字符串规定一个序,如果上面两个形成的数字前者大,那么就规定 s 1 < s 2 s_1<s_2 ,如果后者大则不等号反向,如果一样大则规定两个字符串相等。
我们首先证明,这确实是个偏序关系:自反性和反对称性显然;对于传递性,如果 s 1 s 2 s_1\le s_2 并且 s 2 s 3 s_2\le s_3 ,我们要证明 s 1 s 3 s_1\le s_3 。以下所有式子,我们直接以 s s 来表示字符串 s s 代表的数字,令 l i l_i 代表 s i s_i 的长度。那么问题转化为:已知: s 1 1 0 l 2 + s 2 s 2 1 0 l 1 + s 1 s 2 1 0 l 3 + s 3 s 3 1 0 l 2 + s 2 s_110^{l_2}+s_2\ge s_210^{l_1}+s_1\\s_210^{l_3}+s_3\ge s_310^{l_2}+s_2 要证明: s 1 1 0 l 3 + s 3 s 3 1 0 l 1 + s 1 s_110^{l_3}+s_3\ge s_310^{l_1}+s_1 由已知得: s 1 ( 1 0 l 2 1 ) s 2 ( 1 0 l 1 1 ) s 2 ( 1 0 l 3 1 ) s 3 ( 1 0 l 2 1 ) s_1(10^{l_2}-1)\ge s_2(10^{l_1}-1)\\s_2(10^{l_3}-1)\ge s_3(10^{l_2}-1) 所以 s 1 ( 1 0 l 2 1 ) ( 1 0 l 3 1 ) s 3 ( 1 0 l 1 1 ) ( 1 0 l 2 1 ) s_1(10^{l_2}-1)(10^{l_3}-1)\ge s_3(10^{l_1}-1)(10^{l_2}-1) s 1 ( 1 0 l 3 1 ) s 3 ( 1 0 l 1 1 ) s_1(10^{l_3}-1)\ge s_3(10^{l_1}-1) 整理即得。
显然任意两个字符串都是可比较的,所以这个偏序关系是个全序关系。而题目给定的数字肯定只有有限个,所以可以证明这个关系也是个良序关系,所以就可以进行排序了。

接着只需证明排好序后一个接着一个拼接起来所得的数就是最大数。可以用反证法。假设 s 1 s 2 . . . s n s_1\le s_2\le ...\le s_n ,但存在一种拼接使得 i < j i<j ,但 s i s_i 的位置在 s j s_j 的后面的拼接方式能得到更大的数,由于显然数字 s i + s i + 1 . . . + s j 1 + s j s j + s i + 1 . . . + s j 1 + s i s_i+s_{i+1}...+s_{j-1}+s_j\ge s_j+s_{i+1}...+s_{j-1}+s_i (因为让不等号左边的 s i s_i 不停向后挪动一直挪到尾部,再将 s j s_j 不停向前挪动一直挪到头部,就得到了不等号右边。然而,每次挪动都会使得数字变小或不变,绝不可能使得数字变大),这就矛盾了。证明完毕。

代码如下:

import java.util.Arrays;

public class Solution {
    /**
     * @param nums: A list of non negative integers
     * @return: A string
     */
    public String largestNumber(int[] nums) {
        // write your code here
        String[] numbers = new String[nums.length];
        for (int i = 0; i < nums.length; i++) {
            numbers[i] = String.valueOf(nums[i]);
        }
    
        Arrays.sort(numbers, (n1, n2) -> (n2 + n1).compareTo(n1 + n2));
        StringBuilder sb = new StringBuilder();
        for (String number : numbers) {
            sb.append(number);
        }
     
     	// 删掉开头的0
        int i = 0;
        while (i < sb.length() && sb.charAt(i) == '0') {
            i++;
        }
        
        // 如果sb全是0,那显然返回0;否则返回前置0去掉后的子串
        if (i == sb.length()) {
            return "0";
        } else {
            return sb.substring(i);
        }
    }
}

时间复杂度 O ( n log n ) O(n\log n) ,空间 O ( n ) O(n)

发布了354 篇原创文章 · 获赞 0 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/qq_46105170/article/details/105324262
今日推荐