算法模版:KMP模板及字符串经典模拟【沈七】

前言

唤我沈七就好啦。

字符串

KMP:高效查找子串

ne[j] 作用:记录模式串中 j 之前的最长的相等前后辍

这样当出现不匹配的时候后

可以直接跳转到 以前一个字符 结尾的 公共最长前后辍 的前缀 的后面

例如下面这个例子

 s:  abbabfab

 p:  abbabc

当前位置时

s串的'f'与p串的'c'不匹配

kmp的思想是:跳转到 以'c'前面的'b'字符结尾的 公共最长前后辍 的 前缀 的后面 

即 前缀 ab 后面 'b'位置

 s:  abbabfab

 p:   abbabc
#include<bits/stdc++.h>
using namespace std;
const int N = 1e7+10;
int n,m;
int ne[N];
char s[N],p[N];
int main()
{
    
    
  cin>>s+1>>p+1;
  n=strlen(s+1),m=strlen(p+1);
  
  生成 ne【】数组 ,这里利用了动态规划的思想
  for(int i =2 , j = 0 ;  i <= m ; i ++)
  {
    
    
     while(j&&p[i]!=p[j+1])j=ne[j];
     if(p[i]==p[j+1])j++;
     ne[i]=j;
  }
  利用ne【】数组,增强匹配效率
  
  for(int i = 1 , j = 0; i <= n ; i ++)
  {
    
    
    while(j&&s[i]!=p[j+1])j=ne[j];
    if(s[i]==p[j+1])j++;
    if(j==m)
    {
    
    
      printf("%d\n",i-m+1);
      j=ne[j];
  }
  for(int i = 1 ; i <= m ; i ++)
  printf("%d ",ne[i]);
}

如果读者读到现在对 KMP 的实现原理还是一头雾水,我的建议是 背。
当然 背模板的前提是你最起码 已经 ne【】数组的含义了,至于生成 ne【】数组的过程。
如果你实在对其原理感兴趣 ,可以访问网站 AcWing,那里会有对KMP的讲解 。

验证子串(暴力解法)

#include<bits/stdc++.h>
using namespace std;
const int N = 1e7+10;
int n,m;
int ne[N];
char s[N],p[N];
void kmp(int n,string a,string b)
{
    
    
	for(int i = 0 ; i < n ; i ++)
	{
    
    
		int j = 0 ,k=i;
		while(a[k++]==b[j++]&&a[k-1]!=0)continue;
		if(j==b.size()+1)
		{
    
    
			cout<<b+" is substring of "+a;
			return ; 
		}
	}
	cout<<"No substring";
	return ;
}
int main()
{
    
    
   string a,b;
   cin>>a>>b;
   if(a.size()>b.size())
   kmp(a.size(),a,b);
   else
   kmp(b.size(),b,a);
   
}

字符串经典模拟

删除字符后辍

给定一个单词,如果该单词以er、ly或者ing后缀结尾,则删除该后缀(题目保证删除后缀后的单词长度不为0), 否则不进行任何操作。

将后辍的首字母设成 ‘\0’ 这样就不会打印后辍部分了

#include<stdio.h>
#include<string.h>
int main()
{
    
    
	int i,j,m,n;
	char a[100];
	gets(a);
	n=strlen(a);
	if(a[n-2]=='e'&&a[n-1]=='r')
	a[n-2]=0;
	else if(a[n-3]=='i'&&a[n-2]=='n'&&a[n-1]=='g')
	a[n-3]=0; 
	else if(a[n-2]=='l'&&a[n-1]=='y')
	a[n-2]=0;
	printf("%s",a);
	return 0;
}

最长最短单词

给定一句英文句子找出最长与最短的单词。

while(cin>>a)

输入数据 需要

按 Ctrl + Z + 回车

#include<bits/stdc++.h>
using namespace std;
int ans,cnt=99999;
int main()
{
    
    
	string a,b,c;
	while(cin>>a)
	{
    
    
		if(a.size()>ans) 
		{
    
    
			b=a;
			ans=a.size();
		}
		if(a.size()<cnt)
		{
    
    
			c=a;
			cnt=a.size();
		}
	}
	cout<<b<<"\n"<<c;
	return 0;
}

翻转单词

输入一个句子(一行),将句子中的每一个单词翻转后输出。

hello world
olleh dlrow
#include<bits/stdc++.h>
using namespace std;
int main()
{
    
    
	string a,b;
	getline(cin,a);
	for(int i = 0; i <= a.size(); i ++)
	{
    
    
		if(a[i]==' '||a[i]==0)
		{
    
    
			for(int j = i-1;a[j]!=' '&&j>=0; j --)
			cout<<a[j];
			cout<<" ";
		}
	}
	return 0;
}

完结散花

ok以上就是对 算法模版:数论之约数全家桶 的全部讲解啦,很感谢你能看到这儿。如果有遗漏、错误或者有更加通俗易懂的讲解,欢迎小伙伴私信我,我后期再补充完善。

参考文献

https://www.acwing.com/activity/content/19/

猜你喜欢

转载自blog.csdn.net/m0_66139206/article/details/123642197