劍指offer_45_把陣列排成最小的數
把陣列排成最小的數
題目連結:https://leetcode-cn.com/problems/ba-shu-zu-pai-cheng-zui-xiao-de-shu-lcof/
題目內容:
輸入一個非負整數陣列,把數組裡所有數字拼接起來排成一個數,列印能拼接出的所有數字中最小的一個。
示例 1:
輸入: [10,2]
輸出: "102"
示例 2:
輸入: [3,30,34,5,9]
輸出: "3033459"
提示:
- 0 < nums.length <= 100
說明:
- 輸出結果可能非常大,所以你需要返回一個字串而不是整數
- 拼接起來的數字可能會有前導 0,最後結果不需要去掉前導 0
題目解析
題目解析內容來自於題解中Krahets 和 bigkjp97
分析
題目的意思首先要明確,不是說把列表中每個數拆分開,而是,將數組合起來,組成一個最小的數。
這就轉換成了讓這個列表按照組合後數字最小的模式排序。也就是說,要定一個規則,使得列表中的數字按照這個規則從小到大排序。
現在我們就來找這個排序規則:
這裡放一個示例,供大家理解。
test_list = [3, 30, 34, 5, 9] # 示例列表
由題意,當 '30' + '3' = '303', '3' + '30' = '330' 時,'303' < '330', 則可知 '30' + '3' < '3' + '30', 也即 30 應該在陣列按照規則排序後應排在 3 前面。
同理, '30' + '34' = '3034', '34' + '30' = '3430', '3034' < '3430', 則 '30' + '34' < '34' + '30', 即 30 在 34 前面。
照此邏輯,可以類推。
則可以得出這個排序規則:x + y < y + x ===> x < y
根據這個規則,使用任何一種排序方法都可以對 指定列表進行排序,從而得到最小的排列結果。
演算法流程:
- 初始化:根據數字列表生成字串列表
- 字串列表排序:根據上面發現的規則進行字串列表的排序
- 返回:拼接字串列表為字串,並返回
複雜度分析:
- 時間複雜度 O(NlogN)
- 空間複雜度 O(N): 字串列表 佔用線性大小的額外空間
程式碼
快排方式
class Solution:
def minNumber(self, nums):
def fast_sort(strs):
if len(strs) <= 1:
return strs
less, greater = [], []
p = strs.pop()
for i in strs:
if i + p < p + i:
less.append(i)
else:
greater.append(i)
print(less, greater, p, type(p))
return fast_sort(less) + [p] + fast_sort(greater)
strs = [str(num) for num in nums]
res = fast_sort(strs)
return ''.join(res)
內建函式方式
class cmpSmaller(str):
def __lt__(self, y):
return self + y < y + self # 字串拼接比較(兩兩比較)
# 按由小到大來排列
class Solution:
def minNumber(self, nums):
res=sorted(map(str, nums),key=cmpSmaller)
smallest = ''.join(res)
return smallest
sort 是隻可比較 list 型別;sorted 可比較所有可迭代物件
附加說明
快排方式,無需多言。內建函式,實可深究。
內建函式方式自定義了一個類 comSmaller
繼承了 str
類。並且重寫了其 __lt__
方法。這個方法就是當程式使用 <
比較時,程式內部呼叫的方法。具體解析可點此瞭解
至於為什麼 sorted
排序指定的 key
為 comSmaller
類,在下是在難以深究,忘大佬賜教。以供更改此文件。