题目

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

示例 1:

输入: [10,2]
输出: “102”

示例 2:

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

提示:

0 < nums.length <= 100
说明:

输出结果可能非常大,所以你需要返回一个字符串而不是整数
拼接起来的数字可能会有前导 0,最后结果不需要去掉前导 0

思路

看到题目第一反应这不就是先将数字转为字符串,然后按字典序排序,拼接起来就好了嘛。

但是一用类库排序一试并不对,有一种情况会出错,比如类似剑指 Offer 45. 把数组排成最小的数 - 图1剑指 Offer 45. 把数组排成最小的数 - 图2剑指 Offer 45. 把数组排成最小的数 - 图3的字典序大,但是这个题中应该排在剑指 Offer 45. 把数组排成最小的数 - 图4的前面,因为’’剑指 Offer 45. 把数组排成最小的数 - 图5‘’比’’剑指 Offer 45. 把数组排成最小的数 - 图6‘’更小,所以还是要另想办法。

那既然剑指 Offer 45. 把数组排成最小的数 - 图7剑指 Offer 45. 把数组排成最小的数 - 图8小,意味着决定两个数哪个在前的因素是拼接的顺序,可以推测对于剑指 Offer 45. 把数组排成最小的数 - 图9剑指 Offer 45. 把数组排成最小的数 - 图10两个字符串,如果剑指 Offer 45. 把数组排成最小的数 - 图11小于剑指 Offer 45. 把数组排成最小的数 - 图12的字典序,那么剑指 Offer 45. 把数组排成最小的数 - 图13就应该放在剑指 Offer 45. 把数组排成最小的数 - 图14前面。举个例子,还是对于剑指 Offer 45. 把数组排成最小的数 - 图15#card=math&code=30%28%E8%AE%B0%E4%BD%9Ca%29&id=Ot1uM)和剑指 Offer 45. 把数组排成最小的数 - 图16#card=math&code=3%28%E8%AE%B0%E4%BD%9Cb%29&id=rArLy),因为剑指 Offer 45. 把数组排成最小的数 - 图17#card=math&code=303%28a%2Bb%29&id=u0tGx)小于剑指 Offer 45. 把数组排成最小的数 - 图18#card=math&code=330%28b%2Ba%29&id=L0FcE),所以剑指 Offer 45. 把数组排成最小的数 - 图19要放在剑指 Offer 45. 把数组排成最小的数 - 图20前面。那这个排序规则是不是对于多个字符串也成立呢,即是不是具有传递性,如果a<b,b<c,是否一定有a<c呢,举几个例子倒是成立,不过严谨的证明也不简单,「这里」有人给出了证明。

代码

  1. class Solution {
  2. public String minNumber(int[] nums) {
  3. int n = nums.length;
  4. String[] arr = new String[n];
  5. for (int i = 0; i < n; i++) {
  6. arr[i] = String.valueOf(nums[i]);
  7. }
  8. Arrays.sort(arr, (a, b) -> (a + b).compareTo(b + a));
  9. StringBuilder sb = new StringBuilder();
  10. for (int i = 0; i < n; i++) {
  11. sb.append(arr[i]);
  12. }
  13. return sb.toString();
  14. }
  15. }