面试题45. 把数组排成最小的数
描述:输入一个非负整数数组,把数组里所有数字拼接起来排成一个数,打印能拼接出的所有数字中最小的一个。
示例 1:
输入:[10,2]
输出: "102"
证明过程:
-
当只有一个元素时,即 Input = [A]时,则最小数为A
-
当存在两个元素时,即 Input=[A,B]时,则最小数为 min([int(str(A)+str(B)),int(str(B)+str(A))])
-
当超过两个元素时,设后面字母都代表数字对应的字符串,设最小数为ABCDE,
(1)若int(BA)小于int(AB),则最小数应该为BACDE,矛盾,同理可得,相邻两个变量之间有int(前面的变量 + 后面的变量) < int(后面的变量+ 前面的变量)的关系
(2)此时,证明无论相隔多远,都有在最小数字符串中都有int(前面的变量 + 后面的变量) < int(后面的变量+ 前面的变量)的关系。
具体地,当最小句子为LOPATYUBCVN时,,则该句子可变为YAXBZ,其中Y,X,Z为其他字母合成的表示符,其中Y=LOP,X=TYU,Z=CVN,固定Y,X,Z的组合。设其A,X,B,Y,Z的长度分别为a, x, b, y, z。
则根据(1)有,通过A,B的邻居X建立A和B的关系
i n t ( A X B Z ) ≤ i n t ( X A B Z ) → A × 1 0 x + b + z + X × 1 0 b + z + B × 1 0 z + Z ≤ X × 1 0 a + b + z + A × 1 0 b + z + B × 1 0 z + Z → A × 1 0 x + X ≤ X × 1 0 a + A → A × ( 1 0 x − 1 ) ≤ X × ( 1 0 a − 1 ) → A × 1 0 x − 1 1 0 a − 1 ≤ X int(AXBZ)\leq int(XABZ) \newline \rightarrow A \times 10^{x+b+z} +X\times10^{b+z}+B\times10^z+Z\leq X \times 10^{a+b+z}+A\times10^{b+z}+B\times10^z+Z \newline \rightarrow \mathbf{A \times 10^x +X \leq X \times 10^a+A} \newline\rightarrow \mathbf{A\times(10^x-1) \leq X\times(10^a-1)}\newline \rightarrow \textcolor{red}{\mathbf{A\times \frac{10^x-1}{10^a-1} \leq X}} int(AXBZ)≤int(XABZ)→A×10x+b+z+X×10b+z+B×10z+Z≤X×10a+b+z+A×10b+z+B×10z+Z→A×10x+X≤X×10a+A→A×(10x−1)≤X×(10a−1)→A×10a−110x−1≤X
i n t ( X B Z ) ≤ i n t ( B X Z ) → X × 1 0 b + z + B × 1 0 z + Z ≤ B × 1 0 x + z + X × 1 0 z + Z → X × 1 0 b + B ≤ B × 1 0 x + X → X ≤ B × 1 0 x − 1 1 0 b − 1 int(XBZ)\leq int(BXZ) \newline \rightarrow X \times 10^{b+z} +B\times10^{z} + Z \leq B \times 10^{x+z}+X\times10^{z}+Z \newline \rightarrow \mathbf{X \times 10^b +B \leq B \times 10^x+X}\newline\rightarrow \textcolor{red}{\mathbf{X \leq B\times\ \frac{10^x-1}{10^b-1}}} int(XBZ)≤int(BXZ)→X×10b+z+B×10z+Z≤B×10x+z+X×10z+Z→X×10b+B≤B×10x+X→X≤B× 10b−110x−1
从而有, A × 1 0 x − 1 1 0 a − 1 ≤ X ≤ B × 1 0 x − 1 1 0 b − 1 \mathbf{A\times\frac{10^x-1}{10^a-1}\leq X \leq B\times \frac{10^x-1}{10^b-1}} A×10a−110x−1≤X≤B×10b−110x−1,
即, A × 1 0 b + B ≤ B × 1 0 a + A → i n t ( A B ) ≤ i n t ( B A ) \textcolor{red}{\mathbf{A\times10^b+B\leq B \times 10^a +A\rightarrow int(AB)\leq int(BA)}} A×10b+B≤B×10a+A→int(AB)≤int(BA),特别地,当Y,Z为空字符串时,易证上式也成立。
综上所述,对于构成最小数字的字符串而言,任意两个字母之间有int(previous+later) > int(later+previous) 的关系。
解决方案:
根据上述证明,我们知道形成最小数的字符串,两个字母之间存在int(previous+later) > int(later+previous) 的关系,则我们可以定义一种比较方法,其伪代码如下所示:
def cmp_function(A:int,B:int):
"""
:params A 表示一个数字
:params B 表示一个数字
:return True if A{<=}B else False
"""
return int(str(A)+str(B)) <= int(str(B)+str(A))
通过该比较方法,我们使用快速排序对原列表进行从小到大排序,便可得到构成最小数的列表顺序,其代码如下所示:
class Solution:
def minNumber(self, nums: List[int]) -> str:
# 快排排序
def partition(nums,left,right):
temp = nums[left]
l,r = left,right
while l < r:
while not cmp_function(nums[r],temp) and l < r:
r-=1
nums[l] = nums[r]
while cmp_function(nums[l],temp) and l < r:
l+=1
nums[r] = nums[l]
r -= 1
nums[l] = temp
return l
def quickSort(nums,left,right):
if left >= right:
return
mid = partition(nums,left,right)
quickSort(nums,left,mid-1)
quickSort(nums,mid+1,right)
return
quickSort(nums,0,len(nums)-1)
return ''.join([str(item) for item in nums])