题目描述
Froggy 分别给出 10 个数码的出现次数,你需要找到一个由这些数码组成的最小的数,满足:
1. 这个数是回文的。
2. 不能有前导 0。
注:假设这个数字长度是 L,那么这个数是回文的当且仅当对于任意的 i∈[1,L],第 i 位的数码和第 L−i+1位的数码相同。
快来帮帮 Froggy 吧!
输入描述:
一行 10 个自然数,分别表示数码 0∼9 的出现次数。
输出描述:
如果无解,只输出 “-1”。(不含引号)
否则,输出一个数表示最小的解。
备注:
保证输入的所有数都不超过 10,且至少有一个数大于 0。
思路简述:
1.输入次数是按照从0到9的顺序输入的,这样输入也使得我们在最后找最小数字的时候,如果第一位是0字符,可以直接将第一位字符和1字符交换,这样得到的就是最小的数字
2.同时我们得考虑输入每个字符的次数是否是偶数,如果是偶数,当然可以构成回文数字,但如果有奇数,得分情况,如果只有一个奇数,那么只要将这个字符放在中间即可,但如果是两个奇数次数的字符,那么就不能构成回文字符。所以下面的mid就是起这样的一个功能
3.对于可以成对出现的字符,我们只要将一个存储在ans之中即可。这样会使得我们在最后输出回文字符的时候只要将ans逆置即可、
#include <iostream>
#include <algorithm>
using namespace std;
int main()
{
int times = 0;
string mid, ans;
for (int i = 0; i < 10; i++)
{
cin >> times;//输入该字码出现的次数
//先判断这个次数是不是偶数
if (times & 1)//二级制按位且。如果是奇数,就运行下面的语句
mid += ('0' + i);//这里表示在字符串末尾+上一个字符,这些字符就表示次数是奇数的字码
for (int j = 0; j < times / 2; j++)//表示循环的是次数的一半
ans += ('0' + i);//表示的是每一个字码的次数的偶数次的一半
//这里的mid是保存的字码是否是奇数,ans表示的是偶数次/2,也就是说ans中出现了一个字符,就表示这个字符的实际次数是2次
}
if (mid.size() > 1)//size获取的是字符串mid的长度
puts("-1");//表示的是奇数的字符超过了1个,就不能成立,是因为如果是一个字符多出来,我们可以将这个字符放在中间,构成回文字符,如果不止一个,就不能放在中间构成回文字符
else//表示是0或者1的情况
{
int k = 0;
while (k < ans.size() && ans[k] == '0')
k++;
if (k == ans.size() && k != 0)//这里得考虑完全,如果出现了0字符,但是只是出现了0字符,就得考虑首字母是否是0的情况
puts("-1");
else
{
swap(ans[k], ans[0]);//将第一个不为0的字码和0交换
cout << ans << mid;//这里的ans只是一半的数据,而且要的是最小的数,按照上面的得到ans和mid的方法,我们得到的就是升序的字符串,所以上面只需要将第一个0字符换为非1字符即可
reverse(ans.begin(), ans.end());//将ans字符串首位倒置,得到的是回文字符串
cout << ans<<endl;
}
}
return 0;
}