LeetCode Largest Number

LeetCode解题之Largest Number


原题

给定一组非负整数,将这些整数拼接成最大的数字。由于返回的数字可能非常大,直接返回字符串。

注意点:

例子:

输入: nums = [3, 30, 34, 5, 9]

输出: ‘9534330’

解题思路

要将这些数字拼接起来,其实就是要规定好这些数字出现的先后顺序,所以我们要对这些数字进行排序。直接比较数字的大小是行不通的,如12和121,虽然121>12,但是12121>12112。应有的排序规则应该是如果AB>BA,那么我们规定A>B,也就是最后拼接时A放在B之前。这个方案看着有点道理,而且也是正确的,但要证明按照这种排序得到的数字是最大的比较困难。

以下证明参考自@19thhell。主要要说名两点,一是这种比较关系具有传递性,第二是按照这样的拼接顺序得到的数是最大的。

首先,通过证明传递性可以帮我得到所有数的大小关系:

    为了方便表示,定义f(X) = 10^(lgX + 1), (lgX + 1)表示X有多少位,所以AB = f(B)A + B
    假设 A <· B, B <· C (<·是为了与一般的小于号区分)
    即 AB < BA, BC < CB
    因为 AB < BA
    f(B)A + B < f(A)B + A
    (f(B) - 1)A < (f(A) - 1)B
    A < B·(f(A) - 1) / (f(B) - 1)   (1)

    因为 BC < CB
    f(C)B + C < f(B)C + B
    (f(C) - 1)B < (f(B) - 1)C
    B < C·(f(B) - 1) / (f(C) - 1)   (2)

    结合 (1), (2),
    A < C·(f(A) - 1) / (f(C) - 1)
    (f(C) - 1)A < (f(A) - 1)C
    f(C)A + C < f(A)C + A
    AC < CA
    即得到了A <· C

    根据传递性可以得到按照上面的比较规则排序后的数字满足A1 ·> A2·> ... ·> A(n-1)

下面证明A1A2…A(n-1)是这些数能够拼接成的最大的数字。

如果A < B,那么我们容易得到CAD < CBD(这里是一般的大小关系) (3)

因为 A1 ·> A2·> ... ·> A(n-1)
所以 A1Aj > AjA1, 再根据(3)有以下的大小关系
(A1B)C...N > (BA1)C...N
B(A1C)...N > B(CA1)...N -> A1BC...N > BCA1...N
...
... -> A1BC...N > BCA...NA1
也就是说A1放在第一个位置相对于把它放在其他的位置时,拼接出来的数字大。同理我们也可以推断出A2应该放在第二位......

综上所述,我们通过将数字按照上述方法排序后再拼接就可以得到最大的数字。还有需要注意的是可能参数是多个0,此时字符串拼接的结果是一串0,不符合常规的表达方法,要将其改为0。

AC源码

from functools import cmp_to_key


class Solution:
    # @param {integer[]} nums
    # @return {string}
    def largestNumber(self, nums):
        sorted_nums = sorted(map(str, nums), key=cmp_to_key(lambda x, y: int(y + x) - int(x + y)))
        result = ''.join(sorted_nums).lstrip('0')
        return result or '0'


if __name__ == "__main__":
    assert Solution().largestNumber([3, 30, 34, 5, 9]) == '9534330'
    assert Solution().largestNumber([0, 0]) == '0'

欢迎查看我的Github (https://github.com/gavinfish/LeetCode-Python) 来获得相关源码。

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值