剑指 Offer 45. 把数组排成最小的数

79 阅读1分钟

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第1天,点击查看活动详情 

Leetcode : leetcode-cn.com/problems/ba…

GitHub : github.com/nateshao/le…

剑指 Offer 45. 把数组排成最小的数

题目描述 :输入一个非负整数数组,把数组里所有数字拼接起来排成一个数,打印能拼接出的所有数字中最小的一个。

难度:中等

示例 1:

 输入: [10,2]
 输出: "102"

示例 2:

 输入: [3,30,34,5,9]
 输出: "3033459"

凡是查找,那就很容易想到排序 不说了,快排安排上 通过快排实现排序,排序后转成string

func minNumber(nums []int) string {
   res := make([]string, len(nums))
   for i,v := range nums {
      res[i] = strconv.Itoa(v)
   }
   compare := func(str1, str2 string) bool {
      num1, _ := strconv.Atoi(str1+str2)
      num2, _ := strconv.Atoi(str2+str1)
      if num1 < num2 {
         return true
      }
      return false
   }
   var quickSort func(strArr []string, l,r int)
   quickSort = func(strArr []string, l, r int) {
      if l >= r {
         return
      }
      i, j, pivot := l, r, strArr[l]
      for i < j {
         for i < j && compare(pivot, strArr[j]) {
            j--
         }
         for i < j && !compare(pivot, strArr[i]) {
            i++
         }
         strArr[i], strArr[j] = strArr[j], strArr[i]
      }
      strArr[i], strArr[l] = strArr[l], strArr[i]
      quickSort(strArr, l, i-1)
      quickSort(strArr, i+1, r)
   }
   quickSort(res, 0, len(nums)-1)
   ans := ""
   for _, s := range res {
      ans += s
   }
   return ans
}

image.png 貌似一看,没啥思路。不妨换一个角度,a + b < b + a; Java版快排

    public static String minNumber1(int[] nums) {
         String[] strs = new String[nums.length];
         for(int i = 0; i < nums.length; i++)
             strs[i] = String.valueOf(nums[i]);// 转化为String类型
         quickSort(strs, 0, strs.length - 1);
         StringBuilder res = new StringBuilder();
         for(String s : strs){
             res.append(s);
         }
         return res.toString();
     }
 ​
     /**
      * 快排
      * @param strs
      * @param left
      * @param right
      */
     public static void quickSort(String[] strs, int left, int right) {
         if(left >= right) return;
         int i = left, j = right;
         String tmp = strs[i];
         while(i < j) {
             while((strs[j] + strs[left]).compareTo(strs[left] + strs[j]) >= 0 && i < j) j--;
             while((strs[i] + strs[left]).compareTo(strs[left] + strs[i]) <= 0 && i < j) i++;
             tmp = strs[i];
             strs[i] = strs[j];
             strs[j] = tmp;
         }
         strs[i] = strs[left];
         strs[left] = tmp;
         quickSort(strs, left, i - 1);
         quickSort(strs, i + 1, right);
     }
 ​

思路: 此题求拼接起来的最小数字,本质上是一个排序问题。设数组nums中任意两数字的字符串为x和y,则规 定排序判断规则为:

  • 若拼接字符串 x + y > y + x,则 x 大于 y;(比如 x = "7",y="6";x+y=“76” > y+x = "67",即 x > y:7 > 6)
  • 反之,若 x + y < y + x , 则 x 小于 y ; x “小于” y代表:排序完成后,数组中x应在y边;“大于"则反之。

根据以上规则,套用任何排序方法对nums执行排序即可。

算法流程:

  1. 初始化:字符串列表strs,保存各数字的字符串格式;
  2. 列表排序:应用以上“排序判断规则",对strs执行排序;
  3. 返回值:拼接strs中的所有字符串,并返回。

复杂度分析:

  • 时间复杂度O(NlogN) :N为最终返回值的字符数量( strs列表的长度≤N ) ;使用快排或内置函数的平均时间复杂度为O(NlogN),最差为O(N^2)。
  • 空间复杂度O(N) :字符串列表strs占用线性大小的额外空间。
 package com.nateshao.sword_offer.topic_35_minNumber;
 ​
 import java.util.Arrays;
 import java.util.Comparator;
 ​
 /**
  * @date Created by 邵桐杰 on 2021/12/11 17:03
  * @微信公众号 千羽的编程时光
  * @个人网站 www.nateshao.cn
  * @博客 https://nateshao.gitee.io
  * @GitHub https://github.com/nateshao
  * @Gitee https://gitee.com/nateshao
  * Description: 剑指 Offer 45. 把数组排成最小的数
  * https://leetcode-cn.com/problems/ba-shu-zu-pai-cheng-zui-xiao-de-shu-lcof/
  */
 public class Solution {
 ​
     public static void main(String[] args) {
         int[] nums = {10, 2};
         int[] nums2 = {3, 30, 34, 5, 9};
         System.out.println("minNumber(nums) = " + minNumber(nums));// minNumber(nums) = 102
         System.out.println("minNumber(nums2) = " + minNumber(nums2));// minNumber(nums2) = 3033459
         System.out.println("minNumber1(nums2) = " + minNumber1(nums2));
         System.out.println("minNumber3(nums2) = " + minNumber3(nums2));
     }
 ​
 
     /**
      * 思路:先将整型数组转换成 String 数组,然后将 String 数组排序,最后将排好序
      * 的字符串数组拼接出来。关键就是制定排序规则。或使用比较和快排的思想,将前
      * 面的数和最后的数比较,若小则放到最前面,最后再递归调用。
      * @param nums
      * @return
      */
     public static String minNumber(int[] nums) {
         if (nums == null || nums.length == 0) return "";
         int len = nums.length;
         String[] str = new String[len];
         StringBuilder sb = new StringBuilder();
         for (int i = 0; i < len; i++) {
             str[i] = String.valueOf(nums[i]);
         }
         Arrays.sort(str, new Comparator<String>() {
             @Override
             public int compare(String s1, String s2) {
                 String c1 = s1 + s2;
                 String c2 = s2 + s1;
                 return c1.compareTo(c2);
             }
         });
         for (int i = 0; i < len; i++) {
             sb.append(str[i]);
         }
         return sb.toString();
     }
 ​
     /**
      * 贪心
      * @param nums
      * @return
      */
     public static String minNumber3(int[] nums) {
         String[] strs = new String[nums.length];
         for (int i = 0; i < nums.length; i++) {
             strs[i] = String.valueOf(nums[i]);
         }
         Arrays.sort(strs, (o1, o2) -> (o1 + o2).compareTo(o2 + o1));
         StringBuilder sb = new StringBuilder();
         for (String str : strs) {
             sb.append(str);
         }
         return sb.toString();
     }
 }

参考文献:leetcode-cn.com/problems/ba…

\