A - 雷同检测
题意很简单,按照其中短的字符串长度直接遍历判断就行。
#include<math.h>
#include<algorithm>
#include<stdio.h>
#include<iostream>
#include<set>
#include<map>
#include<string.h>
using namespace std;
#define ll long long
const int maxn=1e4+100;
int main()
{
char s1[maxn],s2[maxn];
gets(s1);
gets(s2);
int l1=strlen(s1);
int l2=strlen(s2);
l1=min(l1,l2);
for(int i=0;i<l1;i++)
{
if(s1[i]==s2[i]) printf("%d ",i+1);
}
printf("\n");
return 0;
}
B - 首字母大写
字符串基础,可以直接遍历判断
#include<math.h>
#include<algorithm>
#include<stdio.h>
#include<iostream>
#include<set>
#include<map>
#include<string.h>
using namespace std;
#define ll long long
const int maxn=1e4+100;
int main()
{
char str[90];
gets(str);
int a=strlen(str);
for(int i=0;i<a;i++)
{
if(i==0)
{
if(str[i]>=97&&str[i]<=122)
str[0]-=32;
}
else
{
if(str[i-1]==' '||str[i-1]=='\t'||str[i-1]=='\r'||str[i-1]=='\n')
{
if(str[i]>=97&&str[i]<=122)
str[i]-=32;
}
}
}
puts(str);
return 0;
}
C - 大小写转换
思路:直接遍历判断转换就行,注意是多实例输入。
#include<math.h>
#include<algorithm>
#include<stdio.h>
#include<iostream>
#include<set>
#include<map>
#include<string.h>
using namespace std;
#define ll long long
const int maxn=1e4+100;
int main()
{
char s[maxn];
while(scanf("%s", s) == 1)
{
int l=strlen(s);
for(int i=0;i<l;i++){
if(s[i]>='a'&&s[i]<='z'){
s[i]-=32;
}
}
printf("%s\n",s);
}
return 0;
}
D - 数字反转
本题数据范围1e9,可以直接用数写,不过用字符串更方便些直接从后往前遍历就行(就是特判下负数,如果为负数要先输出负号)
#include<math.h>
#include<algorithm>
#include<stdio.h>
#include<iostream>
#include<set>
#include<map>
#include<string.h>
using namespace std;
#define ll long long
const int maxn=1e4+100;
int main()
{
char s[maxn];
scanf("%s",s);
int l=strlen(s);
ll ans=0;
if(s[0]=='-') printf("-");
for(int i=l-1;i>=0;i--){
if(s[i]!='-') ans=ans*10+(s[i]-'0');
}
printf("%d\n",ans);
return 0;
}
E - 删除单词后缀
题意很简单就是删除3个特殊后缀,后缀长度最大为3很小直接判断后几位就行。
#include<math.h>
#include<algorithm>
#include<stdio.h>
#include<iostream>
#include<set>
#include<map>
#include<string.h>
using namespace std;
#define ll long long
const int maxn=1e4+100;
int main()
{
char s[maxn];
scanf("%s",s);
int l=strlen(s);
if(s[l-1]=='r'&&s[l-2]=='e') l-=2;
else if(s[l-1]=='g'&&s[l-2]=='n'&&s[l-3]=='i') l-=3;
else if(s[l-1]=='y'&&s[l-2]=='l') l-=2;
for(int i=0;i<l;i++){
printf("%c",s[i]);
}
printf("\n");
return 0;
}
F - 判断字符串是否为回文
思路:顺读倒读都一样,那意思就是说字符串前后对称,这就好办了,看str[0]是否等于str[len-1],以此类推,如果不等于就标记然后break退出循环即可。
#include<bits/stdc++.h>
using namespace std;
string st1;
int main(){
cin>>st1;
int len = st1.length();
int j=len-1,flag=0;
for(int i = 0;i < len;i++,j--){
if(st1[i]!=st1[j]) {
flag=1;
break;
}
}
if(!flag) cout<<"yes"<<endl;
else cout<<"no"<<endl;
return 0;
}
G - 基础数据结构——栈(1)
思路:利用栈的机制,第一步先入栈,如果栈底不空且匹配,之后.pop出栈,这样是合法的,如果不合法就flag然后break退出。
#include<string>
#include<map>
#include<stack>
#include<iostream>
#include<algorithm>
using namespace std;
int main(){
string str;
map<char,char> m;
m['(']=')';
m['[']=']';
m['{']='}';
while(getline(cin,str)){
stack <char> vis;
int flag=0;
int len=str.size();
for(int i = 0;i < len;i++){
if(str[i]=='('||str[i]=='['||str[i]=='{'){
vis.push(str[i]);
}
else if(str[i]==')'||str[i]==']'||str[i]=='}')
{
if(vis.size()&&m[vis.top()]==str[i]){
vis.pop();
}
else {
flag=1;
break;
}
}
}
if(!flag&&vis.size()==0){
cout<<"yes"<<endl;
}
else cout<<"no"<<endl;
}
return 0;
}
H - 字典序
判断字符串大小,可以直接调用strcmp函数判断。
#include<math.h>
#include<algorithm>
#include<stdio.h>
#include<iostream>
#include<set>
#include<map>
#include<string.h>
using namespace std;
#define ll long long
const int maxn=1e4+100;
int main()
{
char s[maxn],a[maxn];
scanf("%s",s);
scanf("%s",a);
if(strcmp(s,a)<0) printf("YES\n");
else printf("NO\n");
return 0;
}
I - 验证子串
字符串长度小于200,可以直接暴力判断s1(或s2)是否为子串。
#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int maxn=1e5+10;
int main()
{
string s1,s2;
cin>>s1>>s2;
int l1=s1.size();
int l2=s2.size();
if(l1<=l2){
int i=0;
int j=0,flag=0;
while(j<l2&&i<l1){
if(s2[j]==s1[i]) i++;
j++;
if(i==l1) flag=1;
}
if(flag) cout<<s1<<" is substring of "<<s2<<endl;
else cout<<"No substring"<<endl;
}
else
{
int i=0;
int j=0,flag=0;
while(j<l1&&i<l2){
if(s1[j]==s2[i]) i++;
j++;
if(i==l2) flag=1;
}
if(flag) cout<<s2<<" is substring of "<<s1<<endl;
else cout<<"No substring"<<endl;
}
return 0;
}
J - 子串查找
题意:判断字符串B再A中出现了几次,A,B长度小于1e6。
思路:这是kmp算法的板子题,直接套用kmp算法求解。
关于kmp算法首先要知道next数组的含义,对模式串(也就是B)求next数组,知道next数组的含义就知道kmp匹配为什么快,其次kmp算法最难理解的地方就是如何求解next数组,详情参照下面两篇关于kmp的博客学习:详解kmp算法
从头到尾彻底理解kmp
#include<math.h>
#include<algorithm>
#include<stdio.h>
#include<iostream>
#include<set>
#include<map>
#include<string.h>
#define ll long long
using namespace std;
const int maxn=1e6+100;
char s[maxn],p[maxn];
int nex[maxn],lens,lenp,ans,n;
void getnex(int len)
{
int i=0,j=-1;
nex[0]=-1;
while(i<len)
{
if(j==-1||p[i]==p[j])
{
i++;j++;
nex[i]=j;
}
else j=nex[j];
}
}
void kmp()
{
int i=0,j=0;
while(i<lens)
{
if(j==-1||s[i]==p[j])
{
i++;j++;
}
else j=nex[j];
if(j==lenp)
{
ans++;
j=nex[j];
}
}
}
int main()
{
scanf("%s %s",s,p);
lens=strlen(s);
lenp=strlen(p);
getnex(lenp);
// for(int i=0;i<=lenp;i++) printf("%d ",nex[i]);
// printf("\n");
kmp();
cout<<ans<<endl;
return 0;
}
K - 剪花布条
这道题也是kmp板题,跟上道题很像,唯一区别就是这道题先找到的子串直接就删除的,成功找到一个子串后再匹配模式串就要从头开始(j=0,而不是j=next[j]因为前面的已经被剪了)
#include<math.h>
#include<algorithm>
#include<stdio.h>
#include<iostream>
#include<set>
#include<map>
#include<string.h>
using namespace std;
#define ll long long
const int maxn=1e4+100;
char s[maxn],p[maxn];
int nex[maxn],lens,lenp,ans;
void getnex(int len)
{
int i=0,j=-1;
nex[0]=-1;
while(i<len)
{
if(j==-1||p[i]==p[j])
{
i++;j++;
nex[i]=j;
}
else j=nex[j];
}
}
void kmp()
{
int i=0,j=0;
while(i<lens)
{
if(j==-1||p[j]==s[i])
{
i++;j++;
}
else j=nex[j];
if(j==lenp)
{
ans++;
j=0;
}
}
}
int main()
{
while(~scanf("%s",s))
{
if(strlen(s)==1&&s[0]=='#') break;
scanf("%s",p);
ans=0;
lens=strlen(s);
lenp=strlen(p);
getnex(lenp);
kmp();
printf("%d\n",ans);
}
return 0;
}
L - 最长回文子串
求解最长回文子串有好几种方法,其中Manacher算法是处理的最快的时间复杂度为·O (n)。
关于Manacher算法的原理可以参考下面的博客:
马拉车算法通俗教学
#include <iostream>
#include <cstdio>
#include <cstring>
#define Min(a,b) a>b?b:a
#define Max(a,b) a>b?a:b
#define ll long long
using namespace std;
const int maxn=1e5+10;
int Len[maxn];
char str[maxn],s[maxn];
int n,mx,id,len;
void init()
{
int k=0;
str[k++] = '$';
for(int i=0;i<len;i++){
str[k++]='#';
str[k++]=s[i];
}
str[k++]='#';
len=k;
}
int Manacher()
{
Len[0] = 0;
int sum = 0;
mx = 0;
for(int i=1;i<len;i++)
{
if(i < mx) Len[i] = Min(mx - i, Len[2 * id - i]);
else Len[i] = 1;
while(str[i - Len[i]]== str[i + Len[i]]) Len[i]++;
if(Len[i] + i > mx){
mx = Len[i] + i;
id = i;
sum = Max(sum, Len[i]);
}
}
return (sum - 1);
}
int main()
{
memset(str,0,sizeof(str));
scanf("%s",s);
len = strlen(s);
init();
int temp = Manacher();
printf("%d\n",temp);
return 0;
}
也可以动态规划来求解原理:
动态规划求解最长回文子串
#include<math.h>
#include<algorithm>
#include<stdio.h>
#include<iostream>
#include<set>
#include<map>
#include<string.h>
using namespace std;
const int maxn=1e5+10;
char S[maxn];//A存序列,dp[i]存以i为结尾的连续序列的最大和
int dp[maxn][maxn];
int main()
{
gets(S);//从下标为1开始读入
int len=strlen(S),ans=1;
memset(dp,0,sizeof(dp));
for(int i=0;i<len;i++)
{
dp[i][i]=1;
if(i<len-1)
{
if(S[i]==S[i+1])
{
dp[i][i+1]=1;
ans=2;
}
}
}
//状态转移方程
for(int L=3;L<=len;L++)//枚举子串长度
for(int i=0;i+L-1<len;i++)//枚举子串起始端点 起始端点加上子串长度(子串长度包括他
本身,所以要-1)必须小于总长,
{
int j=i+L-1;//子串右端点
if(S[i]==S[j]&&dp[i+1][j-1]==1)
{
dp[i][j]=1;
ans=L;//更新最长回文子串长度;
}
}
cout<<ans<<endl;
return 0;
}