把数组排成最小的数三种实现方式及时间性能分析

3 篇文章 0 订阅

题目

输入一个正整数数组,将数组里面所有的数字排列成一个数,打印出其中最小的一个。如输入{3,32,321},最小的为321323.

思路

全排列

题目最直接的解法就是将数组中的所有数字全排列,并把每个排列拼接起来,最后输出最小的数字。n个数字总共有n!种排列,其时间性能较差。同时在拼接比较过程中,需要当心大数问题。因此实现时不宜直接使用整形数进行直接比较,同时由于排列后的数据长度均相等,因此应该将其转化为字符串,通过对字符串的比较来确定最终的大小关系。

逐位比较

这种思路主要是从每个数字的高位开始,依次对每一位进行比较。当高位数字较小时,就应当排于前面,当高位数字相同时,依次比较次低位。此外当数字的位数不相等时,就将位数较短的数字的最后一位依次与其余数字比较,直到能够判定最终的排序关系为止。该种算法的时间性能为O(n^2)。

剑指offer中的解答

这种思路主要是定义一种字符串拼接之后的比较规则,通过对拼接字符串的比较来判断两个数字的前后关系,其具体的证明见《剑指offer》。其时间复杂度就等于排序算法的时间复杂度,为O(nlogn)。

代码实现

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.LinkedList;
import java.util.List;

public class PrintMinNumCombineByArray
{
    // 通过全排列比较输出最小值O(n!)
    public static void printMinNum(int [] data)
    {
        if (null == data || 0 == data.length)
        {
            return ;
        }

        String [] str = new String[data.length];
        for (int i = 0; i < data.length; ++i)
        {
            str[i] = String.valueOf(data[i]);
        }

        // 当然也可以直接用int型进行排列
        printMinNum(str);
    }

    public static void printMinNum(String [] data)
    {
        if (null == data || 0 == data.length)
        {
            return ;
        }

        List<String> result = new LinkedList<>();

        permutation(data, 0, result);

        System.out.println(findMin(result));
    }
    private static void permutation(String [] data, int begin, List<String> list)
    {
        if (null == data || data.length == 0 || begin < 0 || begin >= data.length)
        {
            return ;
        }

        if (begin == data.length - 1)
        {
            StringBuilder sb = new StringBuilder();
            for (int i = 0; i < data.length; ++i)
            {
                sb.append(data[i]);
            }
            list.add(sb.toString());
        }

        for (int i = begin; i < data.length; ++i)
        {
            String tmp = data[begin];
            data[begin] = data[i];
            data[i] = tmp;

            permutation(data, begin + 1, list);

            tmp = data[i];
            data[i] = data[begin];
            data[begin] = tmp;
        }
    }

    private static String findMin(List<String> list)
    {
        if (null == list)
        {
            return null;
        }

        StringBuilder minNum = new StringBuilder(list.get(0));
        for (int i = 1; i < list.size(); ++i)
        {
            String num = list.get(i);
            if (num.compareTo(minNum.toString()) < 0)
            {
                minNum.delete(0, minNum.length());
                minNum.append(num);
            }
        }

        return minNum.toString();
    }

    // 时间复杂度是O(n^2),逐位比较
    public static void printMinNumByAno(int [] data)
    {
        if (null == data || data.length == 0)
        {
            return ;
        }

        List<Integer> list = new ArrayList<>();
        for (int item : data)
        {
            list.add(item);
        }

        List<Integer> result = new LinkedList<>();

        while (!list.isEmpty())
        {
            int index = 0;
            int minBits = String.valueOf(list.get(index)).charAt(0) - '0';
            for (int i = 1; i < list.size(); ++i)
            {
                String str = String.valueOf(list.get(i));
                int bits = (int)str.charAt(0) - '0';
                if (bits < minBits)
                {
                    minBits = bits;
                    index = i;
                }
                else if (bits == minBits)
                {
                    String minStr = String.valueOf(list.get(index));
                    int maxLen = str.length() > minStr.length() ? str.length() : minStr.length();
                    for (int k = 1; k < maxLen; ++k)
                    {
                        int sBits = str.charAt(((k > str.length() - 1) ? str.length() - 1 : k)) - '0';
                        int sMinBits = minStr.charAt(((k > minStr.length() - 1) ? minStr.length() - 1 : k)) - '0';

                        if (sBits == sMinBits)
                        {
                            continue;
                        }
                        else if (sBits > sMinBits)
                        {
                            break;
                        }
                        else
                        {
                            minBits = str.charAt(0) - '0';
                            index = i;
                        }
                    }
                }
            }
            result.add(list.remove(index));
        }

        StringBuilder sb = new StringBuilder();
        for (Integer item : result)
        {
            sb.append(item);
        }

        System.out.println(sb.toString());
    }

    // 这种方法的优势是得益于排序方式O(nlogn)
    // 通过定义一个比较器,实现对字符串数组的比较排序
    // 难于想到字符串排序的规则
    public static void printMinNumByBook(int [] data)
    {
        if (null == data || data.length == 0)
        {
            return ;
        }

        String [] str = new String[data.length];
        for (int i = 0; i < str.length; ++i)
        {
            str[i] = String.valueOf(data[i]);
        }

        Arrays.sort(str, new Comparator<String>()
        {
             public int compare(String o1, String o2)
             {
                 StringBuilder sbFir = new StringBuilder(o1);
                 StringBuilder sbSec = new StringBuilder(o2);

                 sbFir.append(o2);
                 sbSec.append(o1);

                 return sbFir.toString().compareTo(sbSec.toString());
             }
        });

        for (int i = 0; i < str.length; ++i)
        {
            System.out.print(str[i]);
        }
        System.out.println();
    }

    public static void main(String [] args)
    {
//      int [] data = {12, 123};
        int [] data = {1, 123, 32, 435, 32212, 124, 222};

        long startTime = System.currentTimeMillis();
        printMinNumByAno(data);
        System.out.println(System.currentTimeMillis() - startTime + "ms.");

        startTime = System.currentTimeMillis();
        printMinNumByBook(data);
        System.out.println(System.currentTimeMillis() - startTime + "ms.");

        startTime = System.currentTimeMillis();
        printMinNum(data);
        System.out.println(System.currentTimeMillis() - startTime + "ms.");
    }
}

性能比较

在main()函数中测试了两种输入数组长度情况下的时间性能,分别为:

短数组

方式1方式2方式3
2ms1ms0ms

长数组

方式1方式2方式3
2ms2ms64ms

通过比较不难发现,在数组长度较短的情况下,通过全排列得出的结果时间性能较优,其余两种方式的时间性能较差;而在长数组的情况下,全排列方式的时间性能急剧下降;此外,也可以发现方式2的时间性能要由于方式1的。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值