把数组排成最小的数
题目描述
输入一个正整数数组,把数组里所有数字拼接起来排成一个数,打印能拼接出的所有数字中最小的一个。例如输入数组{3,32,321},则打印出这三个数字能排成的最小数字为321323。
我的解法1:暴力法
直接遍历所有可能的结果,找出最小值。具体流程是先用二维数组储存所有可能的排列结果,然后遍历所有结果找出最小值,最后把这个最小值转成string即可。但有一点要注意的是在求和的时候如果变量是int型,可能会溢出,所以要定义double型,最后转成string的时候要截掉小数点和小数点之后的字符。此方法时间和空间开销都很大,不建议。
代码见下:
class Solution {
public:
// 计算位数
int countNum(int value)
{
int count = 1;
while (value > 9)
{
value /= 10;
count++;
}
return count;
}
string PrintMinNumber(vector<int> numbers) {
if (numbers.size() == 0) return "";
vector<vector<int> > vec2d;
unordered_set<int> s;
vector<int> vec;
getAllOrders(numbers, vec2d, vec, s);
double sum_min = 0;
for (int j = 0; j < vec2d[0].size(); j++)
{
sum_min = sum_min * pow(10, countNum(vec2d[0][j])) + vec2d[0][j];
}
for (int i = 0; i < vec2d.size(); i++)
{
double curSum = 0;
for (int j = 0; j < vec2d[i].size(); j++)
{
curSum = curSum * pow(10, countNum(vec2d[i][j])) + vec2d[i][j];
}
if (curSum < sum_min) sum_min = curSum;
}
string str = to_string(sum_min);
string str_out;
for (int i = 0; i < str.size(); i++)
{
if (str[i] == '.') break;
str_out.push_back(str[i]);
}
return str_out;
}
// 得到所有的排列,结果存在二维数组中
void getAllOrders(const vector<int> &numbers, vector<vector<int> > &vec2d, vector<int> &vec, unordered_set<int> s)
{
if (vec.size() == numbers.size())
{
vec2d.push_back(vec);
return;
}
for (int i = 0; i < numbers.size(); i++)
{
unordered_set<int> sCur = s;
vector<int> vecCur = vec;
if (sCur.find(i) == sCur.end())
{
vecCur.push_back(numbers[i]);
sCur.insert(i);
getAllOrders(numbers, vec2d, vecCur, sCur);
}
}
}
};
我的解法2:自定义比较规则+排序
我的解法2用的排序,只是在比较大小时是对两个字符串比较,要自定义比较规则。我的思路是这样的:比如比较字符串a(342)和字符串b(3423),先一位位比较,然而直到a遍历结束二者都一样大。我们需要继续比较,要在a后面补位,那么补的值是多少呢?
以此例分析,要比较的两个拼成的数分别是ab和ba,即3423423和3423342,比较这两个数的大小即满足题意。比较过程:从第一位开始,3和3等,4和4等,2和2等,3和3等,4大于3,因此结果出来了。
由上述分析可知,a如果遍历到末尾了仍未分出大小,后面要依次补上b的元素,而因为b的前几位和a的所有位相等,所以补上b的元素等价于补上a的元素。因此遍历a和b字符串比较大小的过程如下:3=3,4=4,2=2,a遍历到末尾仍未分出大小,a的指针重新回到a[0],继续比较a和b,然后当b遍历到末尾仍未分出结果,b同理指针回到b[0]。当满足此条件时不管二者是否相等都要停止比较:遍历次数等于a的size加上b的size的时候,因为两个数拼起来位数就是这么多。
关于排序可用任意算法,我的解法用的快排,其他所有排序算法均可。
代码见下:
class Solution2 {
public:
string PrintMinNumber(vector<int> numbers)
{
string s;
vector<string> vStr = vecIntToStr(numbers);
quickSort(vStr, 0, vStr.size() - 1);
for (int i = 0; i < vStr.size(); i++)
{
s += vStr[i];
}
return s;
}
// int转string
vector<string> vecIntToStr(vector<int> numbers)
{
vector<string> vStr;
for (int i = 0; i < numbers.size(); i++)
{
vStr.push_back(to_string(numbers[i]));
}
return vStr;
}
// 自定义比较逻辑
bool isBiggerOrEqual(string a, string b)
{
int i = 0, j = 0;
int aSize = a.size(), bSize = b.size();
int sizeMax = aSize + bSize;
for(int i = 0; i < sizeMax; i++)
{
// 判断
if (a[i % aSize] > b[i % bSize]) return true;
if (a[i % aSize] < b[i % bSize]) return false;
}
return true;
}
// 快排
void quickSort(vector<string> &vStr, int left, int right)
{
if (left >= right) return;
int i = left, j = right;
string pivot = vStr[left];
while (i < j)
{
while (i < j && isBiggerOrEqual(vStr[j], pivot))
j--;
if (i < j)
vStr[i++] = vStr[j];
while (i < j && isBiggerOrEqual(pivot, vStr[i]))
i++;
if (i < j)
vStr[j--] = vStr[i];
}
vStr[i] = pivot;
quickSort(vStr, left, i - 1);
quickSort(vStr, i + 1, right);
}
};