当前位置: 首页 > 科技观察

送上今年微软的一条笔试题

时间:2023-03-20 20:01:44 科技观察

这里送上一条微软的笔试题,具体题目如下:TimeLimit:10000msCaseTimeLimit:1000msMemoryLimit:256MBDescriptionConsiderastringsetthateachofthem1consideronly{0,eachofthem1}.集合中的所有字符串都有相同数量的0和1。编写一个程序,根据字典顺序查找并输出第K个字符串。如果这样的字符串不存在,或者输入无效,请输出“Impossible”。例如,如果我们有两个'0'和两个'1',我们将有一个包含6个不同字符串的集合,{0011,0101,0110,1001,1010,1100},第4个字符串是1001。输入的第一行输入文件包含一个整数t(1≤t≤10000),测试用例的数量,后面是每个测试用例的输入数据。每个测试用例是3个整数,用空格分隔:N,M(2<=N+M<=33和N,M>=0),K(1<=K<=1000000000)。N代表'0'的个数,M代表'1'的个数,K代表集合中第K个需要输出的字符串。输出对于每种情况,只打印一行。如果字符串存在,请打印它,否则打??印“Impossible”。SampleIn32222274747SampleOut0101Impossible01010111011其实说了这么多,意思很简单,就是输入N个0,M个1,如果不存在就求M,N个1,0组成的第K大数输出是不可能的。对于新人来说,你可能会认为这是一个全排列的问题,但是全排列的问题是你无法知道每个数字排在什么位置,时间肯定不会过去。递归效率大家应该都知道。我们可能会想到另一种解决方案,直接枚举,从最小的000...1111开始,枚举到1111..000,然后记录当前是否包含N个0和M个1。这种方法最容易理解,但是如果数字比较大,比如17个1,17个0,这么大的整数先不说不能存,这时候不划算,虽然是线性的和复杂程度,但这个线性数太大了。..OK,然后我就想是不是可以遍历这棵树,想了想又否决了。终于想到了一个办法,就是通过不断的交流来获得。我们想到如果从第一大数变成第二大数,那么这个数肯定要增加,那么怎么增加呢?为了让这两个数最接近,也就是说我们只增加了1,而不是中间有很多个数?也就是从左往右扫描数据,直到遇到10个,就交换,把1前面的1和第一个0交换。好的思路已经完全暴露了,我这里举个例子。比如5个1和5个0的情况。我们保存的格式是1111100000(实际数是0000011111),这是最小的数(输出的时候倒着输出,这个结构主要是为了方便理解)。***的个数是0000011111。(记住,是倒过来的!)当我们要增加的时候,j=5的时候出现0,j=4的时候就是1,所以我们交换一下,j前面的1=4是和低位0交换的,如果这里没有0,就不用交换了。得到1111010000(实际数为0000101111)。当我们得到0011101100(实际的数字是0011011100),我们应该怎么做才能让这个数字加1呢?很明显,J=5时出现0,j-1=4时交换1,j=4之前的1和最后一位的0开始不断交换,***我们会得到结果:1100011100。(实际号码是00111000011)。好了,到这里大家应该明白了吧,再看看算法源码:【头脑风暴,你有更好的方案吗?]//M:0的个数,N,1的个数,K要输出什么数。booltest(intN,intM,intK){if(calculateTotalNum(M+N,M)bit;map>mapStr;for(inti=0;i=M+N-1)j=0;//已经搜索过***,这个那么你需要tosearchfrombit0if(1==bit[j]&&0==bit[j+1]){intright=j-1,left=0;//从j的前一位开始查找,前面的所有1移到最左边while(right>=0&&bit[right]==1&&leftbit,intM,intN){inti=0;while(ibit,intN){//for(inti=N-1;i>=0;i--)cout<