题目描述:
在十进制表示中,任意一个正整数都可以用字符’0’-‘9’表示出来。但是当’0’-‘9’这些字符每种字符的数量有限时,可能有些正整数就无法表示出来了。比如你有两个‘1’,一个‘2’,那么你能表示出11,12,121等等,但是无法表示出10,122,200等数。
现在你手上拥有一些字符,它们都是’0’-‘9’的字符。你可以选出其中一些字符然后将它们组合成一个数字,那么你所无法组成的最小的正整数是多少?
输入描述:
第一行包含一个由字符’0’-‘9’组成的字符串,表示你可以使用的字符。 1 ≤字符串长度≤ 1000
输出描述:
输出你所无法组成的最小正整数
测试用例1:
输入:1234567890
输出:11
测试用例2:
输入:2233445556677889900111
输出:222
测试用例3:
输入:223344555667788990111
输出:100
解题思路:
本题无法组成的最小数的形式应该只有两种10...0(n个0)或者X...X(X为1到9)。
首先本题要找的是正整数,所以我们先得把0和其他字符分开考虑。
- 先记录‘1’~‘9’这9个字符出现的次数,然后找到出现次数最小的,这里次数相同时优先找值小的字符,比方说‘2’,‘3’都出现了2次,而其余的除‘0’外都出现了3次或其以上(0出现2次,下一条解释为什么),那么最小不能组成的数是222,和3无关。
- 将‘1’~‘9’中出现的最小次数和‘0’出现的次数比较,注意比较的时候‘0’的出现次数得加1。比方说上一条例子中,‘0’出现的次数为1的话,本题答案为100。所以说a[0]=1(0的次数)+1 <= a[2] = 2(2的次数)时,答案的形式为10...0;而a[0]=2 + 1 > a[2] = 2 时,答案形式为X...X。而且通过这个例子我们了解到答案的长度为最小次数加1(‘0’为加2),比方说1中的例子答案3个2(2出现2次),2中的例子答案100(0出现1次)
- 通过2我们总结出的方法:找‘1’~‘9’出现次数最少且值最小的数,和‘0’出现的次数加1进行比较。这里代码实现的时候为了简化,记录0出现次数的a[0]初值我直接赋为1,其余为0,输入字符串后,记录的0出现的次数比实际出现多了个1,然后排序直接用<algorithm>的stable_sort。num[]数组一开始是每个字符的标号,这时num[0]=0,a[]是对应字符出现的次数。比较函数cmp:两个数x,y出现次数a[x]<a[y]时返回true。sort完后,num[]数组中的num[0]就是出现次数最少的字符了。至于为什么用stable_sort,好处就是次数相同时,值小的排前面。这时我们判断次数num[0]是不是‘0’,如果是的话,就输出1;不是则输出num[0]。之后再输出a[num[0]]个num[0],注意这里a[]并没排序,还是原来的依次为0~9的出现次数。
- 之后我们考虑一下特殊情况:
- 字符出现最小次数为0时,没有什么区别
- 字符出现次数全部一样时,定为k次,比较的时候a[0]=k+1 > a[i](i为1~9),此时被挑出来的是1,根据步骤3中的方法最后的答案为1111...11(一共k+1个1)。而事实上它也的确是最小的不能组成的数。这样就顺利地解决了这道题。
实现代码:
#include<iostream>
#include<algorithm>
using namespace std;
int num[10]={0,1,2,3,4,5,6,7,8,9};
int a[10]={1};//出现的次数,‘0’的次数初值赋为1,其余为0
bool cmp(int x,int y)//设置比较函数,将10个字符按出现次数从少到多排列
{
return a[x]<a[y];
}
int main()
{
string str;
cin>>str;
for(auto c:str)
{
a[c-48]++;//记录字符出现次数
}
stable_sort(num,num+10,cmp);//次数相同时,值小的排在前面
num[0]==0 ? cout<<1:cout<<num[0];
for(int i=0;i<a[num[0]];cout<<num[0],i++);
}