百度筆試題5.1

一:編程題

現有一組共計N個固定的集合(N爲萬量級),每個集合有個從0開始遞增的集合ID,每個集合包含1~MTERMM0~100的量級),希望設計一個程序能夠持續對外服務,輸入是一個TERM數組,輸出其中任意一個集合ID(如果該TERM數組包含該集合的所有TERM),如果找不到輸出-1。要求:

1  時間複雜度最優,能夠在短時間內對大量輸入逐個輸出

2  實現具體的代碼(可以是僞代碼),其中常用的數據結構可以採用標準庫。

3  給出時間複雜度和空間複雜度。

TERM組合集合的文件格式舉例:

TERM_1 空格 TERM_2

TERM_1 空格 TERM_3

TERM_1 空格 TERM_3  TERM_4

輸入的爲TERM數組(說明:TERM爲一個詞,可能是中文,固定字符串表示)

Answer1:

A1:判斷一個集合中的所有TERM是否在輸入數組中,可以使用布隆過濾器。建立位數組大小爲100bit,即12.5B

判斷集合中的term是否都在數組中,如果都在,那麼輸出集合的編號。

Answer2:

1. 千萬不要寫代碼 . 僞代碼即可, 不然容易陷入寫算法, 或者強制算法的坑裏面.不利於後面的分析

2. 時間複雜度小. 這個其實應該是考的對於初始狀態的把握. 如何構造有序的初始環境的問題. 因爲如果完全亂序(集合內變量順序, 與用於查找時集合本身是否有序), 那就只能直接遍歷了, 呵呵 那是不可接受的. 我的考慮是先對集合內進行排序, 再對集合的集合本身進行一個排序. 不過因爲題目有單獨提出ID, 所以其實是告訴我們, 應該用另外的空間去建立索引

3. 可持續運行, 其實應該是最重要的考點. 重點分析如下:

    1> 由於持續運行, 所以每單次查找的開銷應該最小, 所以針對上面說的, 做一個初始的有序環境非常的重要.

2> 同樣由於持續運行, 所以有必要考慮動態增刪的問題. 因此上面說的, 對於集合的集合的排序, 可以使用RBTREE的方式, 可能會比較好.

 

Answer3:(自己)

如果可以使用標準模板庫,那麼使用set存儲每一個集合,然後建立vecotr<set>存儲總集合。查找set中每一個元素是否在term數組中。

這個算法的時間複雜度爲:O(M*N*P),Pterm數組的大小。

可以將時間複雜度降到O(M*N),先將term數組的所有元素通過hash函數在標記數組flag中進行標記,然後遍歷所有集合,對集合中的term進行hash,查看term是否在flag數組中,如果該集合的term都在flag數組中,那麼將這個集合的id輸出。

難點是:如何對每一個term進行hashhash函數如何設定。

 

#include "head.h"

 

//查找term數組

 

int IsExist(string term[],int size,string key)

{

       int flag=0;

      for(int i=0;i<size;i++)

         {

           if(key==term[i])

              {

                flag=1;

                break;

              }

         }

 

         return flag;

}

 

void FindID(vector<set<string> > data,string term[],int size)

{

  int flag=0;

  vector<set<string> >::iterator it=data.begin();

  vector<set<string> >::iterator end=data.end();

 

  //遍歷每一個集合

  int id=1;

  while(it!=end)

  {

       set<string> cur=*it;

       set<string>::iterator sit=cur.begin();

       set<string>::iterator send=cur.end();

       flag=0;

       //term數組中的查找每一個集合的元素

    while(sit!=send)

       {

        flag=IsExist(term,size,*sit);

        if(0==flag)

               break;

        else

            sit++;

       }

 

       if(1==flag)

              printf("%3d",id);

 

       it++;

       id++;

      

  }

 

 

 

 

  printf("/n");

}

 

#define N 4

void testFindID()

{

  vector<set<string> > data;

  set<string> s1;

  s1.insert("a1");

  s1.insert("a2");

 

  set<string> s2;

  s2.insert("a1");

  s2.insert("a2");

  s2.insert("a3");

  s2.insert("a4");

 

  set<string> s3;

  s3.insert("a2");

  s3.insert("a4");

 

  set<string> s4;

  s4.insert("a2");

  s4.insert("a3");

 

  data.push_back(s1);

  data.push_back(s2);

  data.push_back(s3);

  data.push_back(s4);

 

  string term[N]={"a1","a2","a3"};

  FindID(data,term,4);

}

 

void main()

{

testFindID();

}

 

 

Answer4:(自己)

改進Asnwer3,將term數組的每一個term通過hash,記錄每一個元素的位置,然後在遍歷每一個集合的時候,就可以將集合中的元素hash來判斷這個元素是否在term數組中,改進以後,時間複雜度爲OM*N)。

具體的就不寫了,下面是使用字符串hash的例子。

#include<iostream>

#include<string>

using namespace std;

const int N=3;

const int MAX = 9973; //哈希表長度

const int len = 30; //字符串的最大長度

 

int Htable[MAX];

char *ch[N]={"abc","def","ghi"};

 

//char ch[MAX][len]; //存儲關鍵字的字符串

//ELF哈希函數

unsigned long Hash(char * key)

{

    unsigned long h = 0;

    while(*key)

    {

        h = (h << 4) + *key++;

        unsigned long g = h & 0xf0000000L;

        if(g)

            h ^= g >> 24;

        h &= ~g;

    }

    return h % MAX;

}

int search(char * key)

{

    unsigned long i = Hash(key);

    while(Htable[i]!=-1)

    {

        if(strcmp(ch[Htable[i]], key) == 0)

            return i;

        i = (i + 1) % MAX;

    }

    return -1;

}

int insert(char * key, int j) //j爲關鍵字在ch中的位置,即索引

{

    unsigned long i = Hash(key);

    while(Htable[i])

        i = (i + 1) % MAX;

       Htable[i] =j;

       printf("%d/n",i);

    return i;

}

 

void main()

{

       int i;

       //初始化hash

       for(i=0;i<MAX;i++)

       {

         Htable[i]=-1;

       }

       //對字符串數組的各元素進行hash

       for(i=0;i<N;i++)

       {

         insert(ch[i],i);

       }

 

       //查找

       printf("please input the string to search:");

       char key[100];

       scanf("%s",key);

       int flag=search(key);

       printf("%d/n",flag);

}

 

 

 

 

 

Answer5:

字符串結合位圖:

#include "head.h"

 

#define HMAX 65535

#define SHIFT 5

#define MASK 0x1f

#define BITSPERWORD 32

#define HSIZE (HMAX/8+1)

 

unsigned long shash(const char *str)

{

  unsigned long h=0;

  while(*str!='/0')

  {

    h=h*31+*str;

       str++;

  }

 

  return h;

}

 

//使用位圖結構實現集合

void sseti(int elem[],int key)

{

  elem[key>>SHIFT] |= 1<<(key&MASK);

}

 

void scleari(int elem[],int key)

{

  elem[key>>SHIFT] &= ~(1<<(key&MASK));

}

 

int sisExist(int elem[],int key)

{

  int flag=0;

  if(elem[key>>SHIFT] & (1<<(key&MASK)) )

         flag=1;

  else

         flag=0;

  return flag;

}

 

void main()

{

       char *pstr[]={"abc","abcd","bce","efg"};

       int size=sizeof(pstr)/sizeof(pstr[0]);

       int i;

       int elem[HSIZE];

       for(i=0;i<HSIZE;i++)

       {

         elem[i]=0;

       }

 

       for(i=0;i<size;i++)

       {

         int h=shash(pstr[i])%HMAX;

         sseti(elem,h);

       }

 

       char str[100];

       printf("please input string:");

       scanf("%s",str);

       int result=shash(str)%HMAX;

       printf("%d/n",sisExist(elem,result));

}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章