A- ZJM 与霍格沃兹 、B-ZJM 与生日礼物 、C-ZJM 与纸条
A:
原题链接
题意就是建立一个字典,格式为:[魔咒] 对应功能,数据量是10 0000条,每条长度最大100。这样的话,我们直接建立map<string,string>会炸掉,需要自己写hash做一个映射。
开始我的思路是:做两个map<int,string>m1,m2,对一个字符串进行取hash,然后查询。但是发现会内存爆掉,然后改用
string a[200010];
map<int,int>mm1,mm2;
来进行建立map,map只存储字符串的下标,就可以过。(map对空间的占用看来是挺大的。
#include<iostream>
#include<map>
#include<string>
const long long int mod= 1e9+7;
using namespace std;
int gethash(string s){
int sum=0;int seed=17;
for(int i=0;i<s.length();i++)
{
sum=(sum+s[i]*seed)%mod;
seed=seed*17%mod;
}
return sum;
}
string a[200010];
map<int,int>mm1,mm2;
int main()
{
//map<int,string>m1,m2;
string s;
int n;int k=0;
while(getline(cin,s) && s!="@END@")
{
string s1,s2;
s1=s.substr(1,s.find(']',0)-1);
s2=s.substr(s.find(']',0)+2);
int h1=gethash(s1);int h2=gethash(s2);
//cout<<s1<<" // "<<s2<<endl;
// m1[h1]=s2;
// m2[h2]=s1;
mm1[h1]=++k;
a[k]=s2;
mm2[h2]=++k;
a[k]=s1;
}
cin>>n;
getchar();
while(n--)
{
getline(cin,s);
if(s[0]=='[')
{
string p=s.substr(1,s.find(']',0)-1);
int t=gethash(p);
map<int,int>::iterator it;it=mm1.find(t);
if(it!=mm1.end())cout<<a[mm1[t]]<<endl;
else cout<<"what?"<<endl;
}
else
{
string p=s;
int t=gethash(p);
map<int, int>::iterator it;it=mm2.find(t);
if(it!=mm2.end())cout<<a[mm2[t]]<<endl; //cout<<"["<<a[mm2[t]]<<"]"<<endl;
else cout<<"what?"<<endl;
}
}
return 0;
}
B:
原题链接
字典树……
我数据结构最后的大课设就是做一个字典树,所以对字典树还是很熟悉的,但是也有些不同。
数据结构课设用的字典树我分别采用指针数组做节点和map做节点实现了两种建立在字母上的26元字典树结构。
这次用的是的是采用数组的方式存储树结构,建立在01串上的字典树。具体怎么解就不写了,直接贴一下代码。
这次的代码:
#include<iostream>
#include<string>
#include<string.h>
using namespace std;
struct Trie{
static const int N=1010,charset =2;
int tot,root,child[N][charset],flag [N];
Trie(){
memset(child,-1,sizeof(child));root=tot=0;
}
void clear(){
memset(child,-1,sizeof(child));
memset(flag ,-1,sizeof(flag));
}
bool insert(char *str){
int now=root,len=strlen(str);
bool jud=false;
for(int i=0;i<len;i++){
int x=str[i]-'0';
if(child[now][x]==-1){
child[now][x]=++tot;
flag[now]=0;
}
else if(i==len-1||flag[child[now][x]])jud=1;
now=child[now][x];
}
flag[now]=1;
return jud;
}
};
int main(){
Trie A; char str[100];
bool ans=true;int cnt=0;bool mark=0;
while(scanf("%s",str)!=EOF)
{
if(str[0]!='9') {
bool t=0;t=A.insert(str);
if(t==true&&mark==0){
ans=false;mark=1;
}
else if(mark==0){
ans=true;
}
}
else
{
printf("Set %d %s\n",++cnt,ans?"is immediately decodable":"is not immediately decodable");
A.clear();
ans=true;mark=0;
}
}
return 0;
}
数据结构课设 map版本
锘?include<iostream>
#include<fstream>
#include<ctime>
#include<map>
#include<unordered_map>
#include<string>
using namespace std;
//鐢╩ap浣滃搱甯岃〃
class Node
{
public:
int line;
bool is_word = false;
unordered_map<char, Node*> children;
~Node()
{
for (int i = 0; i < 26; ++i)
{
if (children.find('a' + i) != children.end()) delete children['a' + i];
}
}
void insert(const string _Word, int line)
{
Node* p = this;
for (int i = 0; i < _Word.size(); ++i)
{
char curr = _Word[i];
if (p->children.find(curr) == p->children.end())
{
p->children.insert(map<char, Node*>::value_type{ curr,new Node() });
}
p = p->children[curr];
}
p->is_word = true;
p->line = line;
}
int has_prefix(const string& _Word)
{
Node* p = this;
int i = 0;
for (; i < _Word.size(); ++i)
{
char curr = _Word[i];
if (p->children.find(curr) == p->children.end())
{
if (p->is_word)return p->line;
else return -1;
}
else
{
p = p->children[curr];
}
}
return -1;
}
};
int main() {
clock_t startTime, endTime;
startTime = clock();//璁℃椂寮€濮?
Node A;
int line = 1;
string temp;
ifstream in("input_1e7.txt");
while (getline(in, temp))
{
A.insert(temp, line);
line++;
}
endTime = clock();//璁℃椂缁撴潫
cout << "The run time is: " << (double)(endTime - startTime) / CLOCKS_PER_SEC << "s" << endl;
return 0;
}
指针版本:
#include<bits/stdc++.h>
using namespace std;
queue< pair<char,int> >q;
struct node{
int line;
char c;
node *child[26];
node(){
line=-1;
c='#';
memset(child,NULL,sizeof(child));
}
};
char ch[26];
void ini(){
for(int i=0;i<26;i++)ch[i]='a'+i;
}
void dfs(node*p){
if(p->line!=-1)
q.push(make_pair(p->c,p->line));
//cout<<p->c<<endl;
for(int i=0;i<26;i++)
{
if(p->child[i]!=NULL)dfs(p->child[i]);
}
}
class trie{
public:
node*root;
public:
trie(){
root=new node;
}
void insert(string s,int line)
{
node*p=root;
for(int i=0;i<s.size()-1;i++)
{
int t=s[i]-'a';
if(p->child[t]==NULL)p->child[t]=new node,p->child[t]->c=s[i];
p=p->child[t];
}
int t=s[s.size()-1]-'a';
if(p->child[t]==NULL)p->child[t]=new node,p->child[t]->c=s[s.size()-1];
p->child[t]->line=line;
}
int exactfind(string s){
node *p=root;
for(int i=0;i<s.size();i++)
{
int t=s[i]-'a';
if(p->child[t]!=NULL)
p=p->child[t];
else {p=NULL;break;}
}
int re;
if(p==NULL)re=-1;else re=p->line;
if(re==-1){cout<<"未找到!"<<endl;return -1;}
else {cout<<"在第"<<re<<"行"<<endl;return 0;}
}
void _delete(string s)
{
int k=exactfind(s);if(k==-1)return;
node *p=root;
for(int i=0;i<s.size();i++)
{
int t=s[i]-'a';
p=p->child[t];
}
p->line=-1;
}
void roughfind(string s)
{
// int k=exactfind(s);if(k==-1)return;
while(q.size())q.pop();
node *p=root;
for(int i=0;i<s.size();i++)
{
int t=s[i]-'a';
if(p->child[t]!=NULL)
p=p->child[t];
else {p=NULL;break;}
}
//cout<<p->c<<" and "<<p->line<<endl;
if(p==NULL){cout<<"未找到!"<<endl;return; }
dfs(p);
}
void list(){
while(q.size())
{
cout<<"在第"<<q.front().second<<"行"<<endl;
q.pop();
}
}
void meun(){
cout<<"0:插入 1:精确查找 2:删除 3:部分查找 5:退出"<<endl;
int op=0;
string ss;int ll;
while(1){
cin>>op;
if(op==5)break;
switch (op)
{
case 0:
cin>>ss>>ll;
this->insert(ss,ll);
break;
case 1:
cin>>ss;
this->exactfind(ss);
break;
case 2:
cin>>ss;
this->_delete(ss);
break;
case 3:
cin>>ss;
this->roughfind(ss);
this->list();
break;
}
}
}
};
int main(){
clock_t startTime,endTime;
startTime = clock();//计时开始
ini();
trie A;
int line=1;
string temp;
ifstream in("input.txt");
while(getline(in,temp))
{
A.insert(temp,line);
line++;
}
endTime = clock();//计时结束
cout << "The run time is: " <<(double)(endTime - startTime) / CLOCKS_PER_SEC << "s" << endl;
A.meun();
return 0;
}
C:
C题是KMP,个人感觉贼难,找一个字符串在另一个字符串中出现的次数。核心思想是建立一个next数组,利用这个next数组进行跳跃式遍历,提高查询效率,降低复杂度。
关于next数组的建立,我的理解是:next[i]存放的是一旦 i 匹配不上,我们该跳到子串的什么位置继续匹配。求next[i]的过程就是找 i 前面字符串的“前缀、后缀最长重合长度”。我们设 i , j 变量分别表示前后缀的最后字符位置,相等,那么都加一,失配,那么 i 回溯到next[i],用这样一种递推似的思想来求出整个next数组。
#include<iostream>
#include<string>
#include<string.h>
using namespace std;
char ptr[10005];
char str[1000005];
int Next[10005];
void getnext(const char ptr[],int len){
Next[0]=0;
for(int i=1,j=0;i<len;++i){
while(j&&ptr[i]!=ptr[j])j=Next[j-1];
if(ptr[i]==ptr[j])j++;
Next[i]=j;
}
}
int kmp(const char str[],const char ptr[]){
int len1=strlen(str);
int len2=strlen(ptr);
int cnt=0;
getnext(ptr,len2);
for(int i=0,j=0;i<len1;++i){
while(j&&str[i]!=ptr[j])j=Next[j-1];
if(str[i]==ptr[j])j++;
if(j==len2){
cnt++;
j=Next[j-1];
}
}
return cnt;
}
int main(){
int n=0;cin>>n;
while(n--){
scanf("%s",ptr);
scanf("%s",str);
cout<<kmp(str,ptr)<<endl;
memset(str,0,sizeof(str));
memset(ptr,0,sizeof(ptr));
memset(Next,0,sizeof(Next));
}
return 0;
}