1.两个整数集合A,B,求其并集,交集,差集,对称差集,要求写出代码
分析: 首先对数组进行排序,如果数组无序的话。
具体可以参考侯捷《STL源码解析》的方法实现。我这里就是参照那里的方
法实现的。详情请见源码。
#include <stdio.h>
#define N 100
int result[N];
void set_union(int* a, int lenA,int* b,int lenB) //并集
{
int i = 0, j = 0,k = 0;
while(true)
{
if(a[i] < b[j])
{
result[k++] = a[i];
i++;
}
else if(a[i] > b[j])
{
result[k++] = b[j];
j++;
}
else
{
result[k++] = a[i];
i++;
j++;
}
if(i >= lenA || j >= lenB)
break;
}
while(i < lenA)
{
result[k++] = a[i];
i++;
}
while(j < lenB)
{
result[k++] = b[j];
j++;
}
}
void set_intersection(int* a, int lenA,int* b,int lenB) //交集
{
int i = 0, j = 0,k = 0;
while(true)
{
if(a[i] < b[j])
{
i++;
}
else if(a[i] > b[j])
{
j++;
}
else
{
result[k++] = a[i];
i++;
j++;
}
if(i >= lenA || j >= lenB)
break;
}
}
void set_difference(int* a, int lenA,int* b,int lenB)
{
int i = 0, j = 0,k = 0;
while(true)
{
if(a[i] < b[j])
{
result[k++] = a[i];
i++;
}
else if(a[i] > b[j])
{
j++;
}
else
{
i++;
j++;
}
if(i >= lenA || j >= lenB)
break;
}
while(i < lenA)
{
result[k++] = a[i];
i++;
}
}
void set_symmetric_difference(int* a, int lenA,int* b,int lenB)
{
int i = 0, j = 0,k = 0;
while(true)
{
if(a[i] < b[j])
{
result[k++] = a[i];
i++;
}
else if(a[i] > b[j])
{
result[k++] = b[j];
j++;
}
else
{
i++;
j++;
}
if(i >= lenA || j >= lenB)
break;
}
while(i < lenA)
{
result[k++] = a[i];
i++;
}
while(j < lenB)
{
result[k++] = b[j];
j++;
}
}
void InitArray(int *a,int n)
{
for(int i = 0; i < n; i++)
a[i] = -1;
}
void PrintArray(int* a, int n)
{
for(int i = 0; i < n; i++)
{
if(a[i] == -1)
break;
else
printf("%d ",a[i]);
}
printf("/n");
}
int main()
{
//if not sorted, sort it first
int A[6] = {1, 3,5,7,9,11};
int B[7] = {1,1,2,3,5,8,13};
InitArray(result,N);
set_union(A,6,B,7);
PrintArray(result,N);
InitArray(result,N);
set_intersection(A,6,B,7);
PrintArray(result,N);
InitArray(result,N);
set_difference(A,6,B,7);
PrintArray(result,N);
InitArray(result,N);
set_difference(B,7,A,6);
PrintArray(result,N);
InitArray(result,N);
set_symmetric_difference(A,6,B,7);
PrintArray(result,N);
return 0;
}
2.腾讯笔试题:需要多少只小白鼠才能在24小时内找到毒药
有1000瓶水,其中有一瓶有毒,小白鼠只要尝一点带毒的水24小时后就会死亡,至少要多少只小白鼠才能在24小时时鉴别出那瓶水有毒?
分析:
最容易想到的就是用1000只小白鼠,每只喝一瓶。但显然这不是最好答案。
既然每只小白鼠喝一瓶不是最好答案,那就应该每只小白鼠喝多瓶。那每只应该喝多少瓶呢?
首先让我们换种问法,如果有x只小白鼠,那么24小时内可以从多少瓶水中找出那瓶有毒的?
由于每只小白鼠都只有死或者活这两种结果,所以x只小白鼠最大可以表示2^x种结果。如果让每种结果都对应到某瓶水有毒,那么也就可以从2^x瓶水中找到有毒的那瓶水。那如何来实现这种对应关系呢?
第一只小白鼠喝第1到2^(x-1)瓶,第二只小白鼠喝第1到第2^(x-2)和第2^(x-1)+1到第2^(x-1) + 2^(x-2)瓶….以此类推。
回到此题,总过1000瓶水,所以需要最少10只小白鼠。
方法1:
为了便于计算,将1000看成1024瓶(其中只有一瓶毒药)。将1024瓶溶液编号1到1024。当只有一只小白鼠的时候,我们可以将1024 瓶溶液对半分,在编号为1---512的瓶子中各取一滴,然后将混合溶液喂给小白鼠,24小时之后,如果小白鼠死亡,则毒药在编号1---512的某个瓶子之中;否则,毒药在编号为513---1024的瓶子当中。如此,便可排除一半的瓶子。
图一
如果有两只小白鼠,首先按前面一步,将编号为1---512 的溶液各取一滴,喂给第一只小白鼠。紧接着,将图一中的512再对半分,如图二所示,此时将编号为1--256 和编号为513---768 的溶液各取一滴,喂给第二只小白鼠。两只小白鼠都有死亡和活着两种可能,故而两只小白鼠在24小时后的状态有四种情况。分别分析这四种情况:两只小白鼠都活着,则说明毒药在编号为之后的256瓶溶液中;第一只小白鼠死亡,第二只小白鼠活着,则说明毒药在编号为257---512(即图二中第二个256)的溶液中;第一只小白鼠活着,第二只小白鼠死亡,则说明毒药在编号为513---768(即图二中第三个256)的溶液中;两只小白鼠都死亡,则说明毒药在编号为1---256(即途中第一个256)的溶液中;
图二
上面两只小白鼠,可以将毒药所在的范围缩小到256瓶,如果给三只小白鼠,按照上面的逻辑,则可以将毒药的范围缩小到128瓶。分析如下:
前两只小白鼠,按照上面的步骤完成,紧接着,将图二中的每个256再对半,此时1024瓶溶液分成了8等份,每一份为128瓶,命名为1到8组。同理,选择256分叉树下的左边的那份,即对应图三中第四行的1,3,5,7组(框住的部分),将这四组溶液各取一滴,喂给第三只小白鼠。三只小白鼠每只都有活着和死亡两种状态,故而小白鼠在24小时后的状态有8中可能,每一种情况对应毒药在8组溶液中的一组。分析省略。
图三
综上继续推下去,即可得知,当有10只小白鼠时,10只小白鼠24小时之后的状态有210种,每一种状态正好对应1024瓶溶液中是毒药的那瓶。喂给每只老鼠的溶液映射关系也容易得出:
第一只小白鼠:1~~1/2 *(1024)
第二只小白鼠:1~~1/4 *(1024) ,2/4 *(1024)~3/4 *(1024)
第三只小白鼠:1~~1/8 *(1024),2/8 *(1024)~~3/8 *(1024),4/8 *(1024)~~5/8 *(1024),6/8 *(1024)~~7/8 *(1024)
```````
第n只小白鼠:1~~1/2n *(1024),2/2n *(1024)~~3/2n *(1024),````,(2n-2)/2n *(1024)~~(2n-1)/2n *(1024)
如何通过10只小白鼠24小时候的状态找出对应的毒药呢?分析如下:
首先命一变量count=0,判断第一只老鼠,如果第一只老鼠死亡,说明毒药在前512之中,此时count不变,如果第一只老鼠活着,说明毒药在后512中,此时count=count+512;判断第二只老鼠,如果第二只老鼠死亡,则count不变,否则,count=count+256;`````;判断第n只老鼠,如果第n只老鼠死亡,则count不变,否则count=count+1/2n *(1024);
定义一个向量,X=(x1,x2,x3,x4,x5,x,x7,x8,x9,x10),其中如果第i只老鼠死亡,则xi=0,否则,xi=1;可得出毒药的编号N为:
N=1/2 *(1024)*x1 + 1/22 *(1024)*x2 + ······ + 1/210 (1024) *x10 + 1
方法2:
把小白鼠从0-9编号;
把药水按1-1000编号;
把药水编号按二进制,如果第i位(因为最大1000,所以bit位为0-9)为1,则分给编号为i的小白鼠喝;
最后统计小白鼠死的编号,并在这些死的小白鼠的编号的对应位置1, 然后得一二进制数,再把这组10位的二进制数转换成十进制数,这个十进制数就是有毒的药水编号。
具体用实例给解析一下:
用 0、1、2、3、4、5、6、7、8、9 给小白鼠编号;
而药水按1-1000编号;
我们把每瓶药水的编号转换为二进制数,由于2的10次方=1024,所以我们将二进制数定为有10个数位,如:
1=0000000001
13=0000001101
214=0011010110
对二进制转换不熟悉的朋友可以用“开始-程序-附件-计算器-查看-科学型”来轻松转换。
这样转换以后,每个药水编号的二进制数的每一位都分别对应一只小白鼠;
我们定义每瓶药水要喂给其二进制编号位数为“1”的那位对应的小白鼠喝;
由于2的10次方=1024>1000,所以这些二进制编号组合都是唯一的;
当我们将1000瓶药水分别喂给相应的小白鼠喝,24小时后,我们统计有中毒症状小白鼠的编号,中毒的定为“1”,正常的定为“0”;
然后依照编号顺序排列,我们就可以得到一个10位的二进制数,而将这个二进制数再转换为十进制数后,这个数值就是有毒的药水的编号了;
例如,最终结果是编号为 2、4、6、7、9 的小白鼠有中毒症状,我们就将一个十位二进制数的2、4、6、7、9位设为“1”,其余各位设为“0”,即:1011010100;
而1011010100对应的十进制数=724,所以第724瓶药水就是有毒药水!
当然,如果都无毒,10只小白鼠就会都是活蹦乱跳的。
如果不好理解,我们假设只有6瓶水,其中有一瓶有毒,2的2次方=4,小于6,2的3次方=8>6,所以至少要3只小白鼠来检测有毒的水瓶,
设小白鼠为A、B、C:
-
A、B、C 编号
-
0 0 0 0
-
0 0 1 1
-
0 1 0 2
-
0 1 1 3
-
1 0 0 4
-
1 0 1 5
-
1 1 0 6
-
1 1 1 7
2的3次方等于8种情况,以上图表知道:A喝第4、5、6、7瓶,B喝第2、3、6、7瓶,C喝1、3、5、7瓶, 上面ABC都是000即是第0瓶不用分给小白鼠喝,或者说小白鼠都活着, 由于ABC都是000时小白鼠都活着,这种情况不可能的,因为至少有一瓶有毒的,所以3只小白鼠实际上只有7种可能。
上面图表说明,比如是C小白鼠死亡而AB活着就知道是编号为1的瓶有毒,又假设是AC死亡,B活着,则是编号5瓶有毒。