数据结构与算法--将数组排成最小的数

将数组排成最小的数
  • 题目:输入一个正整数的数组,将数组中所有数字拼接在一起排列成一个新的数,打印能拼接出来的所有数字中最小的一个,

  • 案例:输入数组{12,4,55},则能打印出最小的数组是:12455

  • 首先还是最简单的做法,我们求出数组中所有数字的全排列,然后将每个排列的情况拼接成一个新的数字,比较得到最小的数字情况。求数组的全排列问题我们在之前的文章:数据结构与算法–字符串的排列组合问题

  • 更具排列组合知识,n个数组共有n!个排列,当数组元素比较多的时候,时间复杂度会是一个非常大的数值,运行会非常慢,应该有更快的方案。

  • 常规优化:穷举法是为了避开了一个选择交换的过程,如果只有两个元素,我们找出小的放到前面,那这个题目就转成了一个找数组的排序规则的过程。数组根据这个排序规则排列成一个最小的数字。要确定排序规则,就需要比较两个数字,也就是给出 m,n两个数,我们需要确定一个排序规则判断m,n那个应该在前面,这不是比较数字大小的问题。

  • 根据题目要求,两个数字m,n,能拼出mn,nm两个数字。

    • 如果mn < nm,那么我们应该输出mn,也就是m应该在n前面,我们定义m 小于 n
    • 如果mn > nm,那么我们应该输出nm,也就是n在m前,我们定义n 小于 m
    • 同样mn = nm定义 m= n
    • 以上中 > < = 是我们数学意义上的比较,而大于,小于,等于,是我们自己定义的大小关系。
  • 那么我们接下来需要考虑的是怎么去拼接数字,当给出数字,m,n,我们直接计算的方式得到mn,nm的关系并不难。但是还有一个关键问题,当mn拼接后得到数字无法用int表达的时候,超过int类型的范围那么我们就不能用普通的计算方式。有一个潜在的大数问题让我必须用字符串的方式来计算。

  • 大数问题用字符串解决,字符串的比较问题,因为此处mn, nm 两个数必然是两个长度相等的字符串,那么比较他大小只需要按照字符串的大小比较规则就可以了。

  • 基于以上分析,我们可以先对数组中的所有数组进行快速排序

  • 排序规则用我们自定义规则,

  • 从小到大排序后,将所有数字依次拼接,就得到了最小值。

  • 经如上分析有如下代码:

/**
 * 将数组中所有数据合并成一个数,求出能排成的最小数
 *
 * @author liaojiamin
 * @Date:Created in 12:00 2021/6/8
 */
public class FinMinNumber {

    public static String pringMinNumber(int[] array) {
        if (array == null || array.length <= 0) {
            return "";
        }
        if (array.length == 1) {
            return String.valueOf(array[0]);
        }
        String[] str = new String[array.length];
        for (int i = 0; i < array.length; i++) {
            str[i] = String.valueOf(array[i]);
        }
        quickSort(str, 0, str.length - 1);
        StringBuilder stringBuilder = new StringBuilder();
        for (String s : str) {
            System.out.print(s +", ");
            stringBuilder.append(s);
        }
        System.out.println();
        return stringBuilder.toString();
    }

    /**
     * 快排法,按从小到大排序字符串,字符串大小规则自定义
     * */
    public static String[] quickSort(String[] str, Integer left, Integer right) {
        if (left < right) {
            Integer temp = quickSortSwap(str, left, right);
            quickSort(str, left, temp - 1);
            quickSort(str, temp + 1, right);
        }
        return str;
    }

    public static Integer quickSortSwap(String str[], Integer left, Integer right) {
        if (left < right) {
            String position = str[left];
            while (left < right){
                while (left < right && myCompareTO(str[right], position) > 0) {
                    right--;
                }
                if (left < right) {
                    str[left] = str[right];
                    left++;
                }
                while (left < right && myCompareTO(str[left], position) < 0) {
                    left++;
                }
                if (left < right) {
                    str[right] = str[left];
                    right--;
                }
            }
           str[left] = position;
        }
        return left;
    }

    /**
     * 字符串大小规则比较,
     * ab > ba => a>b
     * ab == ba => a==b
     * ab<ba =>  a<b
     * */
    public static Integer myCompareTO(String a, String b){
        String ab = a+b;
        String ba = b+a;
        return ab.compareTo(ba);
    }

    public static void main(String[] args) {
        int[] str_1 = {12, 34, 1, 34, 777, 33, 99, 86, 56, 9};
        System.out.println(pringMinNumber(str_1));
    }
}
后续问题
  • 如上实现方案中有两个问题:

    • 第一我定义了一种新的比较两个数的规则,但是这种规则是我们想出来的,并不是定理或者公
    • 第二我们定义的是比较两个数的规则,但是用它来排序一个包含多个数字的数组,最终得到的是否是我们需要的的最小数字?
  • 那么以上两点我们必须给出严格的数学证明,来确保方案的准确:

  • 第一,证明之前订阅的比较规则有效性。一个比较规则有效,需满足三个条件,自反性,对称性,传递性

    • 自反性: 显然,如果ab = ba, 那么 a等于b
    • 对称性: 如果a 小于 b,则ab < ba, 所以ba > ab,因此b 大于 a
    • 传递性: 如果a 小于 b, 则 ab < ba。 假设a, b都是十进制表示时候,分别有1位,m位,有如下推断
      如果有a 小于b
      ab = a * 10 m + b
      ba = b* 101 + a
      若 ab < ba
      有 a * 10 m + b < b* 101 + a
      a * 10 m - a < b* 101 - b
      a(10m-1) < b(101-1)
      a/(101-1) < b/(10m-1)
      同时如果有b 小于c,则bc < cb,同样假设c十进制n位,与以上证明一致,得到
      b/(10m -1) < c(10n -1)
      综上: a/(101-1) < b/(10m-1) < c(10n -1)
      a/(101-1) < c(10n -1)
      a(10n -1) < c(101-1)
      a * 10n + c < c * 101+a
      ac < ca
      a<c
  • 如上证明了这种比较规则满足自反性,对称性,传递性,是一种有效的比较规则,

  • 以下还需要证明根据如上规则将数组排序后,将数组中所有数字拼接起来得到的确实是最小值。

  • 略(太难了)

上一篇:数据结构与算法-- 数组中出现次数超过一半的数字(时间复杂度的讨论)
下一篇:数据结构与算法–丑数

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值