到处转载一些算法,待以后有好点的方法再改进(一)

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/2*(1024),2/2*(1024)~~3/2*(1024),````,(2n-2)/2*(1024)~~(2n-1)/2*(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瓶有毒。

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值