【Golang】LeetCode-剑指Offer-面试题45-把数组排成最小的数【三种解法】

题目

输入一个正整数数组,把数组里所有数字拼接起来排成一个数,打印能拼接出的所有数字中最小的一个。

示例 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的前面
  • 按指定规则进行排序: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
    }
    
}

你可能感兴趣的:(LeetCode力扣个人题解)