一道腾讯笔试的压轴题
有一个江洋大盗,他每次写信都是从一张报纸上剪下单词,再把单词贴在信上。假如某张报纸的单词保存在vector<string>paper 中,而信的单词保存在vector<string>letter 中,写一个算法程序判别该报纸可不可以生成该信?
[解决办法]
letter里面的单词不多的话,直接一个个在paper里面找
很多的话先对paper排个序,二分查找吧
找到一个删一个,全能找到就可以生成,否则不行
效率可能不够高
[解决办法]
1、判断pager和letter的个数,若paper的个数少于letter,则返回false;
2、将pager和letter分别按某一规则排序(减少对比的次数);
3、循环判断letter的内容是否在pager中出现,若出现,将letter中的内容删除,执行查找下一个,如果有一个未找到,则返回false,如都找到,返回true;
4、循环中,当letter中的字符和要找的pager中的字符,要根据排序规则中断查找,换下一个查找。
[解决办法]
哈希会比快排更快点的。
Hash生成两个柱状图。
比较Paper的包含信的就OK了。
[解决办法]
我也觉得用哈希 记录每个单词出现的次数 从letter里拿出一个单词去哈希表里查找 然后-1 如果是负的了 就不成立
[解决办法]
不会用STL的向量容器啊,要是我去面试腾讯的话就杯具了。不过,如果是普通的字符串集合的包含问题,我倒想到了一种很省时的算法,那就是用trie字母树,既节省空间,时间又快。
具体来说就是用对报纸创建一个trie树,然后每输入一个信中的单词就在trie树中查找。比Hash表快、准,不会出现Hash碰撞问题。
关于trie树解决单词重现问题,可以看一下我的这篇博客:
http://blog.csdn.net/qiuzhenguang/archive/2010/03/14/5379310.aspx
[解决办法]
先排序,在二分查找咯
[解决办法]
去问了下高手:先两边hash,hash数组中存该单词出现的次数,然后再比较两个数组相同的下标对象的次数是否是信中的次数小于等于报纸中出现该单词的次数就ok了,时间复杂度是n+m+mm,n是报纸中单词的总个数,m是信中单词的总个数,mm是信中不重复的单词个数,呵呵!
[解决办法]
while(i<paper.length && i<letter.length)
{
if(paper(i)>letter(j))
{j++;}
if(paper(i)==letter(j))
{i++;j++}
if(paper(i)<letter(j))
{return FAUSE}
}
if(i<letter.length)
{return FAUSE}
C++不是很懂,但是算法应该就这样了
[解决办法]
我把报纸上的单词按字母剪开后,就成了一堆字母了,要组成什么样的信都可以啊!
把vector<string>paper中的所有字符映射到map<char,int>A
把vector<string>letter中的所有字符映射到map<char,int>B
A,B中也就A-Za-z的字符,伪代码如下:
foreach(char x:A-Za-z)
{
if(B[x]>A[x])
return false;
}
retuen true;
我一个个字母的剪,这样思考问题么?
[解决办法]
#include <iostream>#include <algorithm>#include <vector>#include <string>#include <map>using namespace std ;vector<string> paper ; //已经初始化好了的 vector<string> letter ; //同上 map<string,int> result ;int main(){ bool flag = true ; vector<string>::iterator p = paper.begin() , l = letter.begin() ; while (p!=paper.end()) ++result[*p++] ; while (l!=paper.end()) { if (result[*l++]<1) { flag = false ; break ; } //就是说paper里没有这个词 } if (flag) cout<<"可以"<<endl ; else cout<<"不可以"<<endl ; return 0 ;}
[解决办法]
#include <string>
#include <iostream>
#include <vector>
#include <set>
using namespace std;
bool IsLetterInPaper(vector <string> paper,vector <string> letter)
{
set <string> set_string;
for(vector <string>::iterator vc_it = paper.begin();vc_it != paper.end();vc_it ++)
{
set_string.insert(*vc_it);
}
for(vector <string>::iterator lt_it = letter.begin();lt_it != letter.end();lt_it ++)
{
if(set_string.insert(*lt_it).second)
return false;
}
return true;
}
int main(int argc, char* argv[])
{
string p[4] = {"I","love","swimming","hate"};
string l[3] = {"I","love","swimming"};
vector <string> paper(p,p + 4);
vector <string> letter(l,l+3);
if(IsLetterInPaper(paper,letter))
cout < < "in paper";
else
cout < <"not in paper";
cout < <endl;
while(1);
return 0;
}
#include <iostream>#include <string>#include <vector>using namespace std;struct node { node *next[26]; //这里假设单词都是26小写字母组成 int cnt; node () : cnt(0) { memset(next,0,sizeof(next)); }};node *root;vector<node*> de; //记录待delete的指针void insert_str(const char *str){ node *p=root; int i=0,j; while (str[i]) { j=str[i]-'a'; if (p->next[j]==0) { p->next[j]=new node; de.push_back(p->next[j]); } p=p->next[j]; i++; } p->cnt++; //记录单词出现的次数}int find(const char *str){ node *p=root; int i=0,j; while (str[i]) { j=str[i]-'a'; if (p->next[j]==0) return 0; p=p->next[j]; i++; } if (p->cnt==0) return 0; else p->cnt--; return 1;}void release(){ size_t i; for (i=0;i<de.size();++i) delete de[i];}int main(){ vector<string> paper(3); paper[0]="abc"; paper[1]="cde"; paper[2]="def"; vector<string> letter(1); letter[0]="cde"; size_t i; //这里可以做一些预处理 //下面针对查找的情况 root=new node; de.push_back(root); for (i=0;i<paper.size();++i) insert_str(paper[i].c_str()); for (i=0;i<letter.size();++i) if (find(letter[i].c_str())==0) { printf("failed!\n"); break; } if (i==letter.size()) printf("succeed!\n");}