题目
输入一个正整数数组,把数组里所有数字拼接起来排成一个数,打印能拼接出的所有数字中最小的一个。
例:
输入数组{3, 32, 321}, 打印321323。
思路
- 排列出所有的组合,比较出最小的,输出。
- 时间复杂度:O(n!)
- 空间复杂度:O(n!)
- 考察最小组合的形式,遵从下面的规律:1、首位小的靠前 2、首位相同,次位小的靠前 3、位数少的靠前。因此等价于比较a + b 和 b + a。下面证明以’a’ + ‘b’ 和 ‘b’ + ‘a’ 的大小顺序排列在多个数字时仍然成立。假设’a’ + ‘b’ 和 ‘b’ + ‘a’。下面证明以’a’ + ‘b’ 和 ‘b’ + ‘a’ 的大小顺序排列在多个数字时仍然成立。假设ab > ba,说明’a’ > ‘b’,则若 bc > cb,‘b’ > ‘c’,有:
a
∗
1
0
D
b
+
b
>
b
∗
1
0
D
a
+
a
a*10^{Db} + b > b*10^{Da} + a
a∗10Db+b>b∗10Da+a,可得
a
/
(
1
0
D
a
−
1
)
>
b
/
(
1
0
D
b
−
1
)
a/(10^{Da} -1) > b/(10^{Db}-1)
a/(10Da−1)>b/(10Db−1),同理,
b
/
(
1
0
D
b
−
1
)
>
c
/
(
1
0
D
c
−
1
)
b/(10^{Db} -1) > c/(10^{Dc}-1)
b/(10Db−1)>c/(10Dc−1),因此
a
/
(
1
0
D
a
−
1
)
>
c
/
(
1
0
D
c
−
1
)
a/(10^{Da} -1) > c/(10^{Dc}-1)
a/(10Da−1)>c/(10Dc−1),所以ac > ca。比较具有传递性。因此只要将普通排序中比较两个元素大小的关系,用字符串比较替代即可。
- 时间复杂度:O(nlogn)使用快排
- 空间复杂度:O(1)
代码
思路2:时间复杂度:O(nlogn),空间复杂度:O(1)
def sort_array_for_min_number(nums):
"""
:param nums: int list
:return: min number string
"""
from functools import cmp_to_key
nums = [str(i) for i in nums]
nums.sort(key = cmp_to_key(lambda a,b:-1 if a + b < b + a else 1))
return ''.join(nums).lstrip('0') or '0'
思考
cmp参数、key参数
python2
list.sort(cmp=None, key=None, reverse=False)
python3
list.sort( key=None, reverse=False)
Python2
list.sort(cmp=None, key=None, reverse=False)
参数
cmp – 可选参数, 如果指定了该参数会使用该参数的方法进行排序。
key – 主要是用来进行比较的元素,只有一个参数,具体的函数的参数就是取自于可迭代对象中,指定可迭代对象中的一个元素来进行排序。
reverse – 排序规则,reverse = True 降序, reverse = False 升序(默认)。
在Python3中没有cmp参数,需要借助functools.cmp_to_key,将用于比较的func转换成key参数需要的函数,在key参数中实现cmp参数的功能。
def cmp_to_key(mycmp):
"""Convert a cmp= function into a key= function"""
class K(object):
__slots__ = ['obj']
def __init__(self, obj):
self.obj = obj
def __lt__(self, other): # less than
return mycmp(self.obj, other.obj) < 0
def __gt__(self, other): # greater than
return mycmp(self.obj, other.obj) > 0
def __eq__(self, other): # equal
return mycmp(self.obj, other.obj) == 0
def __le__(self, other): # less equal
return mycmp(self.obj, other.obj) <= 0
def __ge__(self, other):# greater equal
return mycmp(self.obj, other.obj) >= 0
__hash__ = None
return K
cmp_to_key函数将自定义的cmp函数转换成了一个类K,而K具有使用mycmp函数规定的比较的5种内置方法。list.sort(key = mykey)时,比较a、b两个元素时,实际比较的是mykey(a)、mykey(b)这两个类K的实例,根据比较符号是<、>、==、<=、>=分别调用__lt__、__gt__、__eq__、__le__、__ge__内置方法。此时结果就会是mycmp(a, b)。
因此,在构造mycmp时,我们希望’a’ + ‘b’ >= ‘b’ + 'a’时,mycmp(a, b) > 0 == True。
注意,此处使用lambda可以使运行速度更快。
类似题目
LeetCode 179. 最大数
题目
给定一组非负整数,重新排列它们的顺序使之组成一个最大的整数。
示例 1:
输入: [10,2]
输出: 210
示例 2:
输入: [3,30,34,5,9]
输出: 9534330
说明: 输出结果可能非常大,所以你需要返回一个字符串而不是整数。
代码
class Solution:
def largestNumber(self, nums):
"""
:type nums: List[int]
:rtype: str
"""
from functools import cmp_to_key
nums = [str(num) for num in nums]
nums.sort(key = cmp_to_key(lambda a,b: 1 if a+b<b+a else -1))
return ''.join(nums).lstrip('0') or '0'