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

这里送上一道微软的笔试题,具体题目如下:

Time Limit:
10000ms
Case Time Limit:
1000ms
Memory Limit: 256MB

Description

Consider a string
set that each of them consists of {0, 1} only. All strings in the set have the
same number of 0s and 1s.
Write a
program to find and output the K-th string according to the dictionary order. If
s?uch a string doesn’t exist,
or the
input is not valid, please output “Impossible”. For example, if we have two ‘0’s
and two ‘1’s,
we will have a set with
6 different strings, {0011, 0101, 0110, 1001, 1010, 1100}, and the 4th string is
1001.

Input

The first line of
the input file contains a single integer t (1 ≤ t ≤ 10000),
the number of test cases, followed by the input data
for each test case.
Each test case is 3
integers separated by blank space: N, M(2 <= N + M <= 33 and N , M >=
0),
K(1 <= K <= 1000000000). N
stands for the number of ‘0’s, M stands for the number of ‘1’s,
and K stands for the K-th of string in the set that
needs to be printed as output.

Output

For each case,
print exactly one line. If the string exists, please print it, otherwise print
“Impossible”.

Sample
In

3
2 2 2
2 2
7
4 7 47

Sample
Out

0101
Impossible
01010111011

其实说了这么多,意思很简单,就是输入N个0,M个1.然后求出由M,N个1,0组成的第K大的数。如果不存在则输出impossible.

初来乍到的,大家可能会认为这是一个全排列的问题,但是全排列在问题在于不能很好的知道每个数到底排在第几位,并且时间上肯定是不能通过的,递归的效率大家应该都知道。

我们可能会想到另外一种解决方案,直接列举,从最小的000...1111开始,一直列举到1111..000然后记录下当前是否是含N个0,M个1。这种方式是最容易理解的了,但是如果数字比较大,比如17个1,17个0,我们且不说这么大的整数不能保存,就这个时间上也不合算啊,虽然他是线性复杂度,但是这个线性数也太大了点。。。

OK,我接下来又想到了是否可以通过树的遍历,想了想被我否了。

终于想到了一种方式,就是通过不断的交换获得。我们想到,如果从一个第1大的数变成第2大的数,必然要使这个数增大,那么怎么个增大法?才能使得这两个数是最接近的,也就是说我们只增加了1,而不是中间还存在很多数呢?

那就是从左到右扫描数据,直到遇到10就交换,并且在该1之前的1要和最低位的0交换。好的思路已经完全暴露了,我这里就列举一个例子

比如5个1,5个0的情况。

我们保存的格式是1111100000(实际数为0000011111),它是最小的数(输出的时候倒着输出,这种结构主要为了理解方便)。最大的数是0000011111.(记住,是倒着哈!)

当我们要增加的时候在J=5的时候,出现了0,且j=4时,它为1,这样就交换他们,j=4之前的1和低位的0交换,这里没有0就不需要交换了。得到1111010000(实际数为0000101111).

当我们出现0011101100(实际数为0011011100)要使数字增加1应该怎么做呢?显然,还是J=5时出现了0且j-1=4时为1交换他们,并且j=4之前的1和最低位的0开始不断交换,最后我们会得到结果:1100011100.(实际数为00111000011).

Ok,说到这里大家应该就完全懂了,且看算法源代码:[集思广益,你们有没有更好的解决方案?]


 1 //M:0的个数,N,1的个数。K要输出第几个数。
2 bool test(int N,int M,int K){
3 if(calculateTotalNum(M+N,M)<K)//若实际上的数少于k,返回false,则输出impossible
4 return false;
5 int L=M+N,count=1;
6 bitset<MaxLength> bit;
7 map<int,bitset<MaxLength>> mapStr;
8 for(int i=0;i<M;i++)//初始话最小数,即0都在最左边比如0011
9 bit[i]=1;
10 if(K==1){
11 print(bit,M+N);//输出
12 return true;
13 }
14 int j=0;//表示从低位一直搜索到高位,有没有遇到01,有的话就不断交换。
15 while(!isLast(bit,M,N)){//没有搜索到最后一个数字
16 if(j>=M+N-1)
17 j=0;//已经搜索到最高位了,这个时候就需要从0位搜索
18 if(1==bit[j]&&0==bit[j+1]){
19 int right=j-1,left=0;
20 //从J的前一个搜素,并且该之前的1全部移动到最左边
21 while(right>=0&&bit[right]==1&&left<right){
22 bool temp=bit[right];
23 bit[right]=bit[left];
24 bit[left]=temp;
25 right--,left++;
26 }
27 bit[j]=0;//交换0,1
28 bit[j+1]=1;
29 count++;//统计是第几个大的数了
30 if(count==K){
31 print(bit,M+N);
32 return true;
33 }
34 j=0;//重新回过头来搜素
35 }
36 else
37 j++;
38 }
39 return true;
40 }
41
42 int calculateTotalNum(int N,int M){//组合问题,计算一共多少个数。C(M,N)=A(N,N)/(A(M,M)*A(N-M,N-M))
43 int result=1;
44 for(int i=1;i<=N;i++)
45 result*=i;
46 for(int i=1;i<=M;i++)
47 result/=i;
48 for(int i=1;i<=N-M;i++)
49 result/=i;
50 return result;
51 }
52 bool isLast(bitset<MaxLength> bit,int M,int N){
53 int i=0;
54 while(i<N&&0==bit[i])
55 i++;
56 if(i==N)
57 return true;
58 else
59 return false;
60 }
61 void print(bitset<MaxLength> bit,int N){//
62 for(int i=N-1;i>=0;i--)
63 cout<<bit[i];
64 cout<<"  ";
65 }

附上效果截图:

版权所有,欢迎转载,但是转载请注明出处:潇一

送上今年微软的一道笔试题,布布扣,bubuko.com

时间: 2024-08-04 18:24:01

送上今年微软的一道笔试题的相关文章

关于阿里的一道笔试题分析

其题目如下: ? 1 2 3 4 5 6 7 8 9 10 11 12 13 14 #pragma pack(2) class A { public:     int i;     union U     {         char buff[13];         int i;     }u;     void foo() {    }     typedef char* (*f)(void*);     enum{red, green, blue} color; }a; class A

一道笔试题来理顺Java中的值传递和引用传递

前段时间参加了一场面试,其中有一道引用传递的题,因为当时并没有考虑清楚所以做错了. 现在来复盘一下,题目如下: private static void change(StringBuffer str11, StringBuffer str12) { str12 = str11; str11 = new StringBuffer("new world"); str12.append("new world");} public static void main(Stri

Java中有关构造函数的一道笔试题解析

Java中有关构造函数的一道笔试题解析 1.具体题目如下 下列说法正确的有() A. class中的constructor不可省略 B. constructor必须与class同名,但方法不能与class同名 C. constructor在一个对象被new时执行 D.一个class只能定义一个constructor 2.解析说明 (1)class中的构造函数是可以省略的 /** * @Title:User.java * @Package:com.you.user.model * @Descrip

0810------笔试题----------腾讯2012年的一道笔试题

1.题目要求 a)b[i] = a[0] *a[1] *a[2]*….a[n-1]/ a[i],求出数组b: b)要求不能用除法,除循环控制变量以外,不许额外申请其余变量,时间复杂度为O(n),空间复杂度为O(1). 2.程序思路 a)假设 N = 5,那么 b[0] =      a[1]*a[2]*a[3]*a[4];            b[1] = a[0]*     a[2]*a[3]*a[4];            b[2] = a[0]*a[1]*     a[3]*a[4];

好玩的一道笔试题

/*实现函数: void f(int a, int b, int c) 编码中不允许出现燃和if,switch,for,while之类的关键词以及"?:"表达式,并要求: a=1时,打印b+c的值: a=2时,打印b-c的值: a=3时,打印b*c的值: a=4时,打印b/c的值. */ 下面是我的解答,哈哈: #include <iostream> int cal(int a,int b, int c){ int res = 0; (!(a^1) && (

2015微软实习在线笔试题 - Professor Q&#39;s Software

时间限制:10000ms 单点时限:1000ms 内存限制:256MB 描述 Professor Q develops a new software. The software consists of N modules which are numbered from 1 to N. The i-th module will be started up by signal Si. If signal Si is generated multiple times, the i-th module

给定一个数值,输出符合中国人习惯的读法--记一道笔试题

题目:给定一个数字,最大小于一万亿,输出符合中国人习惯的读法,例如: a.12输出:十二 b.102输出:一百零二 c.1002输出:一千零二 d.112输出:一百十二 e.10112输出:一万零一百十二 f.120000000:一亿二千万 g.11021002:一千一百零二万一千零二 h.11020102:一千一百零二万零一百零二 i.1000001:一百万零一 j.1000000001:十亿零一 嗯,一道笔试题,解的很没有节操,没有太好的思路,只能尽力抽取翻译过程中的共有代码,尽量写的不那么

js原型链的一些发现----来自一道笔试题

1.开篇 1.1本文目标 这是我真正意义上的博客,一是想记录下自己学到的东西,二是想写博客也是对自己的一种历练,自己的一次新的尝试. 废话不多说,说下这次写这篇东东的原因.js的原型链是让我很头疼的事情,每次碰到一些相关的题目和代码都让我有点不知所措.最近的一次笔试碰到了一道相关的题目,不出所料,没有答出来.回来对此钻研一通,不断地查资料测试代码,终于有了点收获,正好最近开始玩博客,所以写了这篇记录. PS:我基础并不好,所以这篇文章可能不会是那种大牛级的专业博客.如果有幸让大神们看到这篇文章,

阿里巴巴的一道笔试题

分布式系统中的RPC请求经常出现乱序的情况. 写一个算法来将一个乱序的序列报序输出,列如,假设起始序号是1,对于(1,2,5,8,10,4,3,6,9,7)这个序列,输出是 1 2 3,4,5 6 7,8,9,10 上述例子中,3到来的时候发现4,5已经在了,因此将已经满足顺序的整个序列(3,4,5)输出为一行. 要求: 1.写一个高效的算法完成上述功能,实现要求尽可能的健壮,易于维护 2.为该算法完成单元测试. 我的思路肯定不是最佳的,只是实现了而已,如果有更好的思路和优化请发送到评论区,谢谢