题目:
输入一个正整数数组,把数组里所有数字拼接起来排成一个数,打印能拼接出的所有数字中最小的一个。例如输入数组{3,32,321},则打印出这三个数字能排成的最小数字为321323。
题目解析:
看到这道题最直接的方法是先求出这个数组中所有数字的全排列,然后将每一种去安排列拼接,然后从拼接中找出最小的数,但是这样的效率明显较低,那么有咩有高效的方法呢?当然有,就是定义一个排序的规则。要定义一个排序的规则,就要比较两个数,假设这两个数是m和n,我们需要确定一个规则来决定那个应该排在前面,这里不仅仅是要对数值的比较。
根据题目的要求,两个数字m和n能拼成数字mn和nm,如果mn>nm,我们就应该让n在前m在后,也就是定义n小于m,反之同理。如果mn=nm,就要定义n等于m。
接下来就要考虑怎么去拼接数字,如果是两个int类型的直接拼接,很有可能就溢出了,所以我们要使用字符串去拼接。既然这样,我们就应该在开始将数组中的整数转换为字符串,这样在拼接的时候就方便多了,并且不用考虑溢出的问题。
一个有效的比较规则需要满足三个条件:自反性、对称性和传递性,那么我们就来证明一下:
自反性:显然有 aa=aa ,所以a = a;
对称性:如果a > b,则有ab > ba,所以ba > ab,则有b > a;
传递性:如果a > b,则有ab > ba。假设a和b用十进制表示时各自有 x位和y位,于是ab = ax10y+b,ba = bx10x+a;传递性如下图:
所以这个比较规则有效。
代码解析:
class Solution {
public://排序规则static bool cmp(int a, int b){string A = "";string B = "";A+=to_string(a);A+=to_string(b);B+=to_string(b);B+=to_string(a);return A<B;}string PrintMinNumber(vector<int> numbers) {if(numbers.empty())return "";string ret = "";sort(numbers.begin(),numbers.end(),cmp);for(size_t i = 0; i < numbers.size(); ++i)ret += to_string(numbers[i]);return ret;}
};