题目
输入一个正整数数组,把数组里所有数字拼接起来排成一个数,打印能拼接出的所有数字中最小的一个。
示例 1:
输入: [10,2]
输出: “102”
示例 2:
输入: [3,30,34,5,9]
输出: “3033459”
提示:
0 < nums.length <= 100
说明:
输出结果可能非常大,所以你需要返回一个字符串而不是整数
拼接起来的数字可能会有前导 0,最后结果不需要去掉前导 0
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/ba-shu-zu-pai-cheng-zui-xiao-de-shu-lcof
解题思路
- 将 数组 转换成 字符串切片 进行排序,因为需要拼接数字
- 排序规则
- 两个数字 m 和 n 能拼接成数字 mn 和 nm
- 如果 mn < nm,那么现在他们的相对位置是正确的
- 如果 mn > nm,那么就需要将n移到m的前面
- 两个数字 m 和 n 能拼接成数字 mn 和 nm
- 按指定规则进行排序:sort.Slice(data interface{},func(i,j int)bool)
- 切片组: data
- 排序的规则:func(i , j int) bool { return ret[i] + ret[j] < ret[j] + ret[i] }
- return true 符合排序的规则则调用 swap(i,j int)
- return strings.Join(ret,""),返回一个以空字符串为间隔连接字符串切片的新字符串
解法一:Sort.Slice( )
–执行用时:0 ms --内存消耗:2.3 MB
func minNumber(nums []int) string {
ret := make([]string,len(nums))
for i,v := range nums{
ret[i] = strconv.Itoa(v)
}
sort.Slice(ret,func(i,j int)bool{
return ret[i] + ret[j] < ret[j] + ret[i]
})
return strings.Join(ret,"")
}
解法二:冒泡排序
–执行用时:16 ms --内存消耗:3 MB
func minNumber(nums []int) string {
var ret string
for i := 0;i < len(nums);i++{
for j := i+1;j < len(nums);j++{
if helper(nums[i],nums[j]){
nums[i],nums[j] = nums[j],nums[i]
}
}
}
for _,v := range nums{
ret += strconv.Itoa(v)
}
return ret
}
//helper 字符串拼接对比大小
func helper(a,b int) bool{
astr := strconv.Itoa(a)
bstr := strconv.Itoa(b)
return astr + bstr > bstr + astr
}
解法三:堆排序
–该解法引用自作者:zeoxc
–执行用时:4 ms --内存消耗:2.7 MB
func minNumber(nums []int) string {
if len(nums) == 0{
return ""
}
out := ""
HeapSort(nums)
for i:=0; i<len(nums); i++{
out += strconv.Itoa(nums[i])
}
return out
}
func sift(list []int, left, right int) {
fIdx := left
sIdx := fIdx*2 + 1
for sIdx <= right{
//判断左孩子:sIdx 右孩子:sIdx+1
if sIdx < right && bigger(list[sIdx], list[sIdx+1]) == list[sIdx+1] {
sIdx++
}
// 最终和大的儿子比较
if bigger(list[fIdx], list[sIdx]) == list[sIdx] {
// 交换
list[fIdx], list[sIdx] = list[sIdx], list[fIdx]
// 交换后重新检查被修改的子节点为大根堆
fIdx = sIdx
sIdx = 2*fIdx + 1
} else {
// 已经是大根堆
break
}
}
}
func HeapSort(list []int) {
length := len(list)
//建立初始堆
sift(list, 0, length-1)
for idx := length / 2; idx >= 0; idx-- {
// 从后往前调整
sift(list, idx, length-1)
}
// 将大根堆的根节点和堆最后一个元素交换,重新对前面的 length - 1 调整堆
for idx := length - 1; idx >= 1; idx-- {
list[0], list[idx] = list[idx], list[0]
sift(list, 0, idx-1)
}
// 结果就是逆序输出大根堆
}
func bigger(a, b int) int{
d, e := strconv.Itoa(a), strconv.Itoa(b)
f := d+e
h := e+d
if f > h{
return a
} else {
return b
}
}