剑指offer[32 把数组排列成最小的数]
题目描述
输入一个正整数数组,把数组里所有数字拼接起来排成一个数,打印能拼接出的所有数字中最小的一个。例如输入数组{3,32,321},则打印出这三个数字能排成的最小数字为321323。
示例1
输入
[3,32,321]
返回值
"321323"
解决方法一:暴力求解
使用itertools.permutations
生成全排列。然后找出全排列中的最小值。时间复杂度O(N!),空间复杂度O(N!),面试必挂率(99.99%)
import itertools
class Solution:
def PrintMinNumber(self, numbers):
# write code here
if not numbers:
return ""
str_num = list(map(str, numbers))
All_way = itertools.permutations(str_num)
res = []
for i in All_way:
res.append(int(''.join(i)))
return min(res)
解决方案二:排序
首先按照我的想法是,此题的比较优质的算法应该会使用到排序,但是如何制定排序规则?
先做个假设使用【1,32,3,321,5】,首先想到的是首位越小放在前面,则应该先将1放在最前面,5放在最后面。现在的话,仅对【32,3,321】如何进行排序更加好呢?比较完首位都是相同的,如何进行进一步的比较就是这道题的难点。
参考了lc
上面的大神的思路:
https://leetcode-cn.com/problems/ba-shu-zu-pai-cheng-zui-xiao-de-shu-lcof/solution/mian-shi-ti-45-ba-shu-zu-pai-cheng-zui-xiao-de-s-4/
- 若拼接字符串 x+y >y +x,则x "大于"y。
- 反之,则x “小于” y。
- 根据此规则对
nums
进行排序即可。
快速排序法:平均时间复杂度O(NlogN)
, 最差时间负杂度O(N^2)
class Solution:
def minNumber(self, nums: List[int]) -> str:
def quick_sort(l , r):
if l >= r: return
i, j = l, r
while i < j:
# 取最左边的数作为基准数,如果 str_i + base >= base + str_i,则可以判断i小于base
while strs[j] + strs[l] >= strs[l] + strs[j] and i < j: j -= 1
while strs[i] + strs[l] <= strs[l] + strs[i] and i < j: i += 1
strs[i], strs[j] = strs[j], strs[i]
strs[i], strs[l] = strs[l], strs[i]
quick_sort(l, i - 1)
quick_sort(i + 1, r)
strs = [str(num) for num in nums]
quick_sort(0, len(strs) - 1)
return ''.join(strs)
冒泡排序法:时间复杂度O(N^2)
class Solution:
def minNumber(self, nums: List[int]) -> str:
nums_str = [str(x) for x in nums]
for i in range(len(nums_str)):
for j in range(1,len(nums_str)-i):
if nums_str[j] + nums_str[j-1] < nums_str[j-1] + nums_str[j]:
nums_str[j],nums_str[j-1] = nums_str[j-1],nums_str[j]
return ''.join(nums_str)