Note4

KMP

详解链接

//从主串中找模式串t出现的所有位置
#include<bits/stdc++.h>
using namespace std;
const int N=1000007;
char t[N],p[N];  //t是主串,p是模式串
int next[N],flag;
void get_next(char p[],int next[]){
	int len=strlen(p),i=0,j=-1;
	next[0]=-1;
	while(i<len){
		if(j==-1||p[i]==p[j]){
			i++;
			j++;
			if(p[i]!=p[j])next[i]=j;
			else next[i]=next[j];	//(next[i]=j;)的优化
		}else j=next[j];
	}
}
void kmp(char p[],int next[]){
	get_next(p,next);
	int i=0,j=0;
	int t_len=strlen(t),p_len=strlen(p);
	while(i<t_len&&j<p_len){
		if(j==-1||t[i]==p[j]){
			i++;
			j++;
		}else j=next[j];
		if(j==p_len){
			printf("%d\n",i-j);	//以0为首地址的位置
			//return;  //找字符串t出现的第一个位置即可的话直接return
			flag=1;
			j=next[j];	//继续匹配
		}
	}
}
int main(){
	cin>>t>>p;
	kmp(p,next);
	//if(!flag)cout<<"Not Find";
}

Trie(字典树)

详解链接

//实现功能:输入n个串,m次查找某个串是否出现过
//n<=10000,m<=100000,每个串长度<=50,只包含小写字母
//trie是以空间换时间,下面的N是节点数
//search可以改一下用来求某个前缀是否出现过
#include<bits/stdc++.h>
using namespace std;
const int N=500010;
struct Trie{	//用struct封装
	int ch[N][26],id,val[N],end[N];
	//ch是子节点,id是编号,val存维护的信息,end判断是否是一个结束 
	Trie(){
		id=1;
		memset(ch[0],0,sizeof(ch[0]));
		memset(val,0,sizeof(val));
		memset(end,0,sizeof(end));
	}//初始化
	void insert(char *s,int value){
		int u=0,len=strlen(s);
		for(int i=0;i<len;i++){
			int v=s[i]-'a';
			if(!ch[u][v])ch[u][v]=id++;
			u=ch[u][v];	//继续向下遍历 
		}
		//val[u]=value;	存维护的信息 
		end[u]=1;
	}
	int search(char *s){
		int u=0,len=strlen(s);
		for(int i=0;i<len;i++){
			int v=s[i]-'a';
			if(!ch[u][v])return 0;
			u=ch[u][v];
		}
		if(end[u])return 1;else return 0;
	} 	
}tree;
int n,m;
char s[100];
int main(){
	cin>>n;
	for(int i=1;i<=n;i++){
		scanf("%s",s);
		tree.insert(s,1);
	}
	cin>>m;
	for(int i=1;i<=m;i++){
		scanf("%s",s);
		int k=tree.search(s);
		if(k)printf("exit\n");
		else printf("not find"); 
	}
}

AC自动机

视频链接
详解链接

//实现功能:给定n个模式串和1个文本串,求有多少个模式串在文本串里出现过 
#include<bits/stdc++.h>
using namespace std;
const int N=500010;
struct AC{	//用struct封装
	int ch[N][26],val[N],fail[N],id;
	void insert(char *s){	//构造Trie树 
		int len=strlen(s),u=0;
		for(int i=0;i<len;i++){
			int v=s[i]-'a';
			if(!ch[u][v])ch[u][v]=++id;
			u=ch[u][v];
		}
		val[u]++;
	}
	void build(){			//bfs构造fail指针 
		queue<int>q;
		for(int i=0;i<26;i++)
			if(ch[0][i]){
				fail[ch[0][i]]=0;
				q.push(ch[0][i]);
			}
		while(!q.empty()){
			int u=q.front();q.pop();
			for(int i=0;i<26;i++)
				if(ch[u][i]){
					fail[ch[u][i]]=ch[fail[u]][i];
					q.push(ch[u][i]);
				}else ch[u][i]=ch[fail[u]][i];
		}
	}
	int query(char *s){
		int len=strlen(s),u=0,ans=0;
		for(int i=0;i<len;i++){
			u=ch[u][s[i]-'a'];
			for(int t=u;t&&~val[t];t=fail[t])ans+=val[t],val[t]=-1;
			//一直向下寻找,直到匹配失败(失败指针指向根或者当前节点已找过).
			//将遍历过后的节点信息标记为-1,防止重复计算
		}
		return ans;
	}
}ac;
int n;
char p[1000007];
int main(){
	scanf("%d",&n);
	for(int i=1;i<=n;i++)scanf("%s",p),ac.insert(p);
	ac.build();
	scanf("%s",p);
	int ans=ac.query(p);
	cout<<ans;
}		

二维前缀和

for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++){
	cin>>sum[i][j];
	sum[i][j]+=sum[i-1][j]+sum[i][j-1]-sum[i-1][j-1];
}
//求(x1,y1)到(x2,y2)的矩形内数的和(包含边上)
ans=sum[x2][y2]-sum[x1-1][y1]-sum[x1][y1-1]+sum[x1-1][y1-1];

发布了17 篇原创文章 · 获赞 7 · 访问量 2075

猜你喜欢

转载自blog.csdn.net/qq_45530271/article/details/103834555