Archive for 11月, 2005

LCS算法

星期三, 11月 30th, 2005

1.最长公共子序列的结构

解最长公共子序列问题时最容易想到的算法是穷举搜索法,即对X的每一个子序列,检查它是否也是Y的子序列,从而确定它是否为X和Y的公共子序列,并且在检查过程中选出最长的公共子序列。X的所有子序列都检查过后即可求出X和Y的最长公共子序列。X的一个子序列相应于下标序列{1, 2, …, m}的一个子序列,因此,X共有2m个不同子序列,从而穷举搜索法需要指数时间。

事实上,最长公共子序列问题也有最优子结构性质,因为我们有如下定理:

定理: LCS的最优子结构性质

设序列X=<x1, x2, …, xm>和Y=<y1, y2, …, yn>的一个最长公共子序列Z=<z1, z2, …, zk>,则:

  1. 若xm=yn,则zk=xm=yn且Zk-1是Xm-1和Yn-1的最长公共子序列;
  2. 若xm≠yn且zk≠xm ,则Z是Xm-1和Y的最长公共子序列;
  3. 若xm≠yn且zk≠yn ,则Z是X和Yn-1的最长公共子序列。

其中Xm-1=<x1, x2, …, xm-1>,Yn-1=<y1, y2, …, yn-1>,Zk-1=<z1, z2, …, zk-1>。

证明

  1. 用反证法。若zk≠xm,则<z1, z2, …, zk ,xm >是X和Y的长度为k十1的公共子序列。这与Z是X和Y的一个最长公共子序列矛盾。因此,必有zk=xm=yn。由此可知Zk-1是Xm-1和Yn-1的一个长度为k-1的公共子序列。若Xm-1和Yn-1有一个长度大于k-1的公共子序列W,则将xm加在其尾部将产生X和Y的一个长度大于k的公共子序列。此为矛盾。故Zk-1是Xm-1和Yn-1的一个最长公共子序列。
  2. 由于zk≠xm,Z是Xm-1和Y的一个公共子序列。若Xm-1和Y有一个长度大于k的公共子序列W,则W也是X和Y的一个长度大于k的公共子序列。这与Z是X和Y的一个最长公共子序列矛盾。由此即知Z是Xm-1和Y的一个最长公共子序列。
  3. 与 2.类似。

这个定理告诉我们,两个序列的最长公共子序列包含了这两个序列的前缀的最长公共子序列。因此,最长公共子序列问题具有最优子结构性质

2.子问题的递归结构

由最长公共子序列问题的最优子结构性质可知,要找出X=<x1, x2, …, xm>和Y=<y1, y2, …, yn>的最长公共子序列,可按以下方式递归地进行:当xm=yn时,找出Xm-1和Yn-1的最长公共子序列,然后在其尾部加上xm(=yn)即可得X和Y的一个最长公共子序列。当xm≠yn时,必须解两个子问题,即找出Xm-1和Y的一个最长公共子序列及X和Yn-1的一个最长公共子序列。这两个公共子序列中较长者即为X和Y的一个最长公共子序列。

由此递归结构容易看到最长公共子序列问题具有子问题重叠性质。例如,在计算X和Y的最长公共子序列时,可能要计算出X和Yn-1及Xm-1和Y的最长公共子序列。而这两个子问题都包含一个公共子问题,即计算Xm-1和Yn-1的最长公共子序列。

与矩阵连乘积最优计算次序问题类似,我们来建立子问题的最优值的递归关系。用c[i,j]记录序列Xi和Yj的最长公共子序列的长度。其中Xi=<x1, x2, …, xi>,Yj=<y1, y2, …, yj>。当i=0或j=0时,空序列是Xi和Yj的最长公共子序列,故c[i,j]=0。其他情况下,由定理可建立递归关系如下:

3.计算最优值

直接利用(2.2)式容易写出一个计算c[i,j]的递归算法,但其计算时间是随输入长度指数增长的。由于在所考虑的子问题空间中,总共只有θ(m*n)个不同的子问题,因此,用动态规划算法自底向上地计算最优值能提高算法的效率。

计算最长公共子序列长度的动态规划算法LCS_LENGTH(X,Y)以序列X=<x1, x2, …, xm>和Y=<y1, y2, …, yn>作为输入。输出两个数组c[0..m ,0..n]和b[1..m ,1..n]。其中c[i,j]存储Xi与Yj的最长公共子序列的长度,b[i,j]记录指示c[i,j]的值是由哪一个子问题的解达到的,这在构造最长公共子序列时要用到。最后,X和Y的最长公共子序列的长度记录于c[m,n]中。

Procedure LCS_LENGTH(X,Y);begin  m:=length[X];  n:=length[Y];  for i:=1 to m do c[i,j]:=0;  for j:=1 to n do c[0,j]:=0;  for i:=1 to m do    for j:=1 to n do      if x[i]=y[j] then        begin          c[i,j]:=c[i-1,j-1]+1;          b[i,j]:="↖";        end      else if c[i-1,j]≥c[i,j-1] then        begin          c[i,j]:=c[i-1,j];          b[i,j]:="↑";        end      else        begin          c[i,j]:=c[i,j-1];          b[i,j]:="←"        end;  return(c,b);end;

由于每个数组单元的计算耗费Ο(1)时间,算法LCS_LENGTH耗时Ο(mn)。

4.构造最长公共子序列

由算法LCS_LENGTH计算得到的数组b可用于快速构造序列X=<x1, x2, …, xm>和Y=<y1, y2, …, yn>的最长公共子序列。首先从b[m,n]开始,沿着其中的箭头所指的方向在数组b中搜索。当b[i,j]中遇到"↖"时,表示Xi与Yj的最长公共子序列是由Xi-1与Yj-1的最长公共子序列在尾部加上xi得到的子序列;当b[i,j]中遇到"↑"时,表示Xi与Yj的最长公共子序列和Xi-1与Yj的最长公共子序列相同;当b[i,j]中遇到"←"时,表示Xi与Yj的最长公共子序列和Xi与Yj-1的最长公共子序列相同。

下面的算法LCS(b,X,i,j)实现根据b的内容打印出Xi与Yj的最长公共子序列。通过算法的调用LCS(b,X,length[X],length[Y]),便可打印出序列X和Y的最长公共子序列。

Procedure LCS(b,X,i,j);begin  if i=0 or j=0 then return;  if b[i,j]="↖" then    begin      LCS(b,X,i-1,j-1);      print(x[i]); {打印x[i]}    end  else if b[i,j]="↑" then LCS(b,X,i-1,j)
                      else LCS(b,X,i,j-1);end; 

在算法LCS中,每一次的递归调用使i或j减1,因此算法的计算时间为O(m+n)。

例如,设所给的两个序列为X=<A,B,C,B,D,A,B>和Y=<B,D,C,A,B,A>。由算法LCS_LENGTH和LCS计算出的结果如图2所示。

j 0 1 2 3 4 5 6
i yj B D C A B A
0 xi 0 0 0 0 0 0
1 A 0 0 0 0 1 1 1
2 B 0 1 1 1 1 2 2
3 C 0 1 1 2 2 2 2
4 B 0 1 1 2 2 3 3
5 D 0 1 2 2 2 3 3
6 A 0 1 2 2 3 3 4
7 B 0 1 2 2 3 4 5

图2   算法LCS的计算结果

5.算法的改进

对于一个具体问题,按照一般的算法设计策略设计出的算法,往往在算法的时间和空间需求上还可以改进。这种改进,通常是利用具体问题的一些特殊性。

例如,在算法LCS_LENGTH和LCS中,可进一步将数组b省去。事实上,数组元素c[i,j]的值仅由c[i-1,j-1],c[i-1,j]和c[i,j-1]三个值之一确定,而数组元素b[i,j]也只是用来指示c[i,j]究竟由哪个值确定。因此,在算法LCS中,我们可以不借助于数组b而借助于数组c本身临时判断c[i,j]的值是由c[i-1,j-1],c[i-1,j]和c[i,j-1]中哪一个数值元素所确定,代价是Ο(1)时间。既然b对于算法LCS不是必要的,那么算法LCS_LENGTH便不必保存它。这一来,可节省θ(mn)的空间,而LCS_LENGTH和LCS所需要的时间分别仍然是Ο(mn)和Ο(m+n)。不过,由于数组c仍需要Ο(mn)的空间,因此这里所作的改进,只是在空间复杂性的常数因子上的改进。

另外,如果只需要计算最长公共子序列的长度,则算法的空间需求还可大大减少。事实上,在计算c[i,j]时,只用到数组c的第i行和第i-1行。因此,只要用2行的数组空间就可以计算出最长公共子序列的长度。更进一步的分析还可将空间需求减至min(m, n)。

字符串中空格去除PDBD[11.12]

星期六, 11月 12th, 2005

/*用下划线代表空格
aa_bb__ccc
应该是碰到第一个_的时候,
就是a后面那个_的时候,
把_和b交换,
就变成aab_b__ccc,
然后我从第一个b继续找_,
 然后再交换_和下一个b,
 就变成aabb___ccc
然后继续找,
下一个非空格是c,
然后交换就变成aabbc___cc
这么做下去就把所有空格推到最后了,
这样不用整体移动字符串 , 一次只交换一个字符
 */
#include "stdafx.h"
#include "stdio.h"
#include "stdlib.h"
#include "string.h"
void reblank(char * str)
{
   if(str==NULL)
    return;
   int length  = strlen(str);
   int j;
   char temp;
   bool inblank  = false;
   for(int i=0;i<length;i++)
   {
     if(str[i]==’ ‘)
     {
           if(!inblank)
           {
            inblank = true;
               j = i ;
           }
  }
     else
   {
        if(inblank)
   {
             temp  = str[j];   
    str[j] = str[i];
    str[i] = temp; 
             inblank = false;
    i = j;
            }
   }

   } 
   str[i+1] = ”; 
}
int main(int argc, char* argv[])
{
 char p[]="he  ll o";
 reblank(p);
 printf("%s\n",p);
 return 0;
}

MSRA一面面经【11.11】

星期五, 11月 11th, 2005
     前天来电话说,上次面的是intern,问我愿不愿意去。
     询问了很多,然后也没说清楚。就说周五去面一下。昨天收到ibm 的 ss 面试通知后,本来想今天就不去了。毕竟做intern意义不大,而且时间紧迫啊。
     10点多msra的电话打来说,如果合适可以提供msra的正式职位。于是欣然前往。
     到msra已经11点多,要面的researcer忙碌中,于是一个北大的哥们出来让我写了几个程序。
     难度并不高,可能昨天晚上睡觉太晚加上今天本来就不想去,一进ms就热的要命。所以程序写的不好。写了一会儿,那哥们儿说就到这儿。偶心里凉啊。怎么这就cut了?
     被告之等招人的researcher面我。
     漫长的等待。。。
     到12点多,面我的大哥进来说,先让我跟他们去吃饭,下午再面,于是跟几个intern一起到sigema B1 吃饭。吃的时候就听他们三个说话了。我也插不上嘴。:(
     回到F5的lab,面试大哥迟迟不回来。上午面我那个哥们(北大的学生也是03 的硕士)&旁边几个intern聊天,期间给我一听cola,没心情啊。
     好不容易等到面试大哥来,于是跟着进入reseracher  room。这位大哥真的很kind,让我一下不是那么紧张。问研究生作的东西的情况。问细节。问数字图像处理算法。然后问了问本科学啥,一听数学,兴奋的不得了。然后我跟他说上午答题不好,没什么好解释的。谁知大哥跟我说,我一看就太紧张。没有发挥出来。ft。。。也许?
      大哥跟我约定让我参加lunch interview。希望我好好准备,放松自己,进入msra。
      表达谢意。大哥送我出门。并再次嘱咐我要自信。
      进电梯,一到家就收到大哥来信,告之我准备好面试就告诉他。
      天底下有这么好的人。真是让我不敢相信。废话很多,努力准备,msra,我来了。

MIT人工智能实验室:如何做研究?

星期四, 11月 10th, 2005

MIT人工智能实验室:如何做研究?》,转载至此,共勉之

【摘要 本文的主旨是解释如何做研究。我们提供的这些建议,对做研究本身(阅读、写作和程序设计),理解研究过程以及开始热爱研究(方法论、选题、选导师和情感因素),都是极具价值的。

备注 人工智能实验室的Working Papers用于内部交流,包含的信息由于过于初步或者过于详细而无法发表。不像正式论文那样,会列出所有的参考文献。】

MSRA的电面经(11。8)

星期三, 11月 9th, 2005
 昨天约好今天电话过来,偶等的心急,打给ms,被接线mm训斥,马上就接到电面电话。
    我以为是某个认识到大哥,就问是不是,然后说不是:(
    首先问项目经历,一个一个问,主要问创新点,算法实现过程,自己的工作职责。问的不算特别细致,中间我回答一个大时候,面官说让我简短介绍自己的东西(
我的表达太差?),于是简单介绍。
    中间问了一个实习时期写的测试工具的事情。对方说这是个小工具,不是平台。
被训斥。:(看来确实要实事求是。
    然后问了问自己简历上面的东西,com。atl等。
    最后面官说等通知。电面结束。

MS 2005.10.16笔试题大全集

星期三, 11月 9th, 2005

声明:取材自本人记忆及各大BBS,如有侵权行为,请尽快通知本人,我将删除相应部分
    1.基本知识,都是选择题,选对1.5,不选0,选错-0.5分, 可多选
包括OS、C、C++、C#、汇编、数据结构、硬件,网络,数据库,题目难度都不大,都是基础的,平时多学多积累,应该没太大问题
一个是给汇编代码,让选择其功能。
一个是SQL题:Transaction执行时是否可以共享读的问题
一个是子网掩码的,问几个选项里有那个是在同一个网段里的
一个是mutex(a key object that only one read-user or write-user or owner^)
一个是cache的write back,要知道什么时候写回动作执行
一个是sorting & LinkedList Double Linkes
一个是网络安全影响到个人隐私(PKI,SSL等等)
一个是看c程序找可能出现的错误(stack,heap overflow,integer overflow^)
一个是C#中的CLR关于GC方向的,与C++相对比
    2.推理题,单选题,要求选最好的答案,共十题(1.5分每个),三小问
有两个小段每个一题
一个是说什么动物(?)身上(头上?)的皮肤裂片不能代表动物的年龄,因为裂片很容易有外界的影响而裂开
另一题是说得了流感(总算看到本专业的词汇喽,呵呵)的, 如果有一个人得了病后继续去上班会传染给别人的
大意是这样吧,英语不咋的,不是记得很清
另一篇题面大意为:现欲举办一场音乐会,组织者准备请四个小提琴家F,G,H,J和五个钢琴家R,S,T,W,Z。会议连续六天,每天只能有一个人表演,每人最多一场。有如下限制:
(1)    如果F表演,则前三天必须都为小提琴表演;
(2)    如果J表演,则必须是在第六天
(3)    如果R表演,则T必须在第一天表演。
(4)    如果W表演,它的前一天和后一天都不能是钢琴表演。
问组织者应如何安排表演?
下边有8个小题左右,都是针对可能情况发问的。随便举一例吧:
下面哪项可能为真?
A.    如果F表演,则W不可能表演。
B.    如果R表演,则W不可能表演。
C.    如果J表演,则F,W不能同时表演
D.    如果W表演,则S,T不能同时表演。

  3.编程题,要求就是不许用递归?好像
第一题是编写一个计算一维数组中所有整数的最大公约数的函数:编写一个函数GetGCD,来求一个数组中N个数的GCD(Greatest Common Demonitor),即最大公约数。并写出尽可能多的测试用例。例如GCD(18,12)=6, GCD(14,35)=7。。。
(1)函数原型如下:int GetGCD(CAryInt & aryInt);
(2)数组访问使用[]操作符,
(3)数组元素个数由CAryInt 的成员函数GetSize获得。
另一题是字典查找,要求设计一合适的字典数据结构,然后编写一查找函数,打印出以给点字符串开头的所有词,例如给出“ab”可以查找出所有以“ab”开头的单词。
  4.设计题:问你对msn message 有什么改进的地方? 有什么新功能可以加的? 如果给你3个月, 你会做些什么? 要用E文写
  5.测试题,Testing部分有两个大题:
第一题为找bug,改bug题。给的程序是判断一个单向链表是否含有环的程序,如果有,返回产生环的第一个结点的指针,否则返回NULL。并写出尽可能多的测试用例
Struct LinkedList {
    LinkedList *pNext;
}
Struct LinkedList *IsCyclicList(struct LinkedList *pHead)
{
    Struct LinkedList *pCur, *pStart;
    While(pCur){
        For(;;){
            If(pCur!=pStart)
                pStart=pStart->pNext;
        }
        pCur = pCur->pNext
    }
}
第二题为:给你一个函数int system(char *command),命令由a-z的26个字母组成,该函数为command字符串的命令解释器,其命令为机器可执行的命令,让你写出尽可能多的测试用例
that’s all