一:編程題
現有一組共計N個固定的集合(N爲萬量級),每個集合有個從0開始遞增的集合ID,每個集合包含1~M個TERM(M爲0~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),P爲term數組的大小。
可以將時間複雜度降到O(M*N),先將term數組的所有元素通過hash函數在標記數組flag中進行標記,然後遍歷所有集合,對集合中的term進行hash,查看term是否在flag數組中,如果該集合的term都在flag數組中,那麼將這個集合的id輸出。
難點是:如何對每一個term進行hash,hash函數如何設定。
#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數組中,改進以後,時間複雜度爲O(M*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));
}