一:编程题
现有一组共计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));
}