题目链接:传送门
密码:202201070000
资料链接:
栈学习资料
kmp详解
小组题解
签到题目
A题雷同检测
思路:暴力
代码:
#include<iostream>
#include<cmath>
#include<string.h>
#include<algorithm>
#include<map>
using namespace std;
typedef long long int ll;
typedef pair<ll,ll> P;
const int maxn=200100;
const int INF=pow(2,31)-1;
const int maxm=5e4+5;
const int mod=1000000007;
char a[1000];
char b[1000];
int main(){
cin.getline(a+1,1000,'\n');
//getchar();
cin.getline(b+1,1000,'\n');
//puts(b+1);
ll n=min(strlen(a+1),strlen(b+1));
for(int i=1;i<=n;i++){
if(a[i]==b[i]){
printf("%d ",i);
}
}
return 0;
}
B - 首字母大写
思路:暴力
代码:
#include<iostream>
#include<string>
using namespace std;
int main(){
string s;
while(getline(cin,s)){
if(s[0] && s[0] >= 'a' && s[0] <= 'z'){
s[0]=s[0]-32;
}
for(int i=0;i<s.length()-1;i++){
if((s[i]==' ' || s[i]=='\t' || s[i]=='\r' || s[i]=='\n') && s[i+1] >= 'a' && s[i+1] <= 'z'){
s[i+1]=s[i+1]-32;
}
}
cout<<s<<endl;
}
return 0;
}
C大小写转换
思路:暴力
代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long int ll;
const ll maxn=1e5+100;
char str[1010];
ll n;
int main(){
while(scanf("%s", str) == 1){
n=strlen(str);
for(int i=0;i<n;i++){
if(str[i]<='z'&&str[i]>='a'){
str[i]-=32;
}
printf("%c",str[i]);
}
printf("\n");
}
return 0;
}
D数字反转
思路:模拟
代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long int ll;
const ll maxn=1e5+100;
char str[1010];
int main(){
cin>>str;
ll flag=0,flag1=0;
if(str[0]=='-'){
flag=1;
printf("-");
}
ll n=strlen(str);
for(int i=n-1;i>=0;i--){
if(!flag1&&str[i]=='0'){
continue;
}
flag1=1;
if(i==0&&flag){
continue;
}else{
printf("%c",str[i]);
}
}
return 0;
}
E - 删除单词后缀
思路:直接判断
代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long int ll;
const ll maxn=1e5+100;
char str[1010];
int main(){
cin>>str;
ll n=strlen(str);
if(str[n-3]=='i'&&str[n-2]=='n'&&str[n-1]=='g'){
str[n-3]='\0';
}else if(str[n-2]=='e'&&str[n-1]=='r'){
str[n-2]='\0';
}else if(str[n-2]=='l'&&str[n-1]=='y'){
str[n-2]='\0';
}else{
}
puts(str);
return 0;
}
F - 判断字符串是否为回文
思路:模拟
代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long int ll;
const ll maxn=1e5+100;
char str[1010],str1[1010];
int main(){
cin>>str;
ll n=strlen(str),flag=0;
for(int i=0,j=n-1;i<n;i++,j--){
str1[j]=str[i];
}
for(int i=0;i<n;i++){
if(str[i]!=str1[i]){
printf("no");
flag=1;
break;
}
}
if(!flag){
printf("yes");
}
return 0;
}
数据结构&&其他算法题目
G - 基础数据结构——栈(1)
思路:首先利用栈结构保存相关符号,并不断消去配对的符号,判断最后是否为空。注意输入的时候可以是空格
代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long int ll;
const ll maxn=1e5+100;
char str[1010];
int judge(char c){
if(c=='{'||c=='}')return 1;
if(c=='('||c==')')return 1;
if(c=='['||c==']')return 1;
return 0;
}
int main(){
while(cin.getline(str,1010,'\n')){
stack<char> st;
ll n=strlen(str);
for(int i=0;i<n;i++){
if(judge(str[i])){
if(st.empty()){
st.push(str[i]);
}else{
char c=st.top();
st.pop();
if(str[i]=='}')
{
if(c!='{'){
st.push(c);
st.push(str[i]);
}
}else if(str[i]==']'){
if(c!='['){
st.push(c);
st.push(str[i]);
}
}else if(str[i]==')'){
if(c!='('){
st.push(c);
st.push(str[i]);
}
}else{
st.push(c);
st.push(str[i]);
}
}
}
}
if(st.empty()){
printf("yes\n");
}else{
printf("no\n");
}
}
return 0;
}
H - 字典序
思路:可以直接用字符串比较函数,这里手写了一下
代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long int ll;
const ll maxn=1e5+100;
char str[10010],str1[10010];
int main(){
cin.getline(str,10010,'\n');
cin.getline(str1,10010,'\n');
ll n=min(strlen(str),strlen(str1));
ll flag=0;
for(int i=0;i<n;i++){
if(str[i]==str1[i]){
continue;
}else if(str[i]<str1[i]){
flag=1;
break;
}else{
flag=2;
break;
}
}
if(flag==0){
if(n==strlen(str)){
flag=1;
}else{
flag=2;
}
}
if(flag==1){
printf("YES");
}else if(flag==2){
printf("NO");
}
return 0;
}
I - 验证子串
思路:首先范围比较小可以进行暴力回溯,这里用kmp进行求解,算是复习。对kmp的直接应用。
代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long int ll;
const ll maxn=1e6+100;
ll nex[maxn];
void getnex(char *str){
nex[0]=-1;
ll j=0,k=-1;
ll n=strlen(str);
while(j<n){
if(k==-1||(str[j]==str[k])){
j++;
k++;
nex[j]=k;
}else{
k=nex[k];//关键步骤
}
}
/*for(int i=0;i<n;i++){
cout<<nex[i]<<" ";
}
cout<<endl;*/
}
bool kmp(char *str,char *str1){
ll i=0,j=0;
ll mn=strlen(str);
ll n=strlen(str1);
//cout<<n<<endl;
ll res=0;
while(i<mn){
if((j==-1)||(str[i]==str1[j])){
i++;
j++;
}else{
j=nex[j];
}
if(j==n){
res++;
}
//cout<<i<<" "<<j<<endl;
}
//cout<<j<<endl;
if(res)return true;
return false;
}
int main(){
char str[1010],str1[1010];
cin>>str;
cin>>str1;
ll flag=0;
ll m=strlen(str);
ll n=strlen(str1);
if(m<n){
flag=1;
}else{
flag=2;
char str2[1010];
strcpy(str2,str);
strcpy(str,str1);
strcpy(str1,str2);
}
getnex(str);
bool k=kmp(str1,str);
if(k){
printf("%s is substring of %s",str,str1);
}else{
printf("No substring");
}
return 0;
}
J - 子串查找
思路:模板题目,对kmp算法的直接应用
代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long int ll;
const ll maxn=1e6+100;
ll nex[maxn];
char str[maxn],str1[maxn];
void getnex(char *str){
nex[0]=-1;
ll j=0,k=-1;
ll n=strlen(str);
while(j<n){
if(k==-1||(str[j]==str[k])){
j++;
k++;
nex[j]=k;
}else{
k=nex[k];//关键步骤
}
}
/*for(int i=0;i<n;i++){
cout<<nex[i]<<" ";
}
cout<<endl;*/
}
ll kmp(char *str,char *str1){
ll i=0,j=0;
ll mn=strlen(str);
ll n=strlen(str1);
//cout<<n<<endl;
ll res=0;
while(i<mn){
if((j==-1)||(str[i]==str1[j])){
i++;
j++;
}else{
j=nex[j];
}
if(j==n){
res++;
}
//cout<<i<<" "<<j<<endl;
}
//cout<<j<<endl;
return res;
}
int main(){
cin>>str;
cin>>str1;
getnex(str1);
ll k=kmp(str,str1);
printf("%lld",k);
return 0;
}
K - 剪花布条
思路:oj原题,直接暴力模拟也可以做,就是当匹配成功后不进行回溯,让变量变为零,其余和上一个·题目差不多
暴力代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long int ll;
const ll maxn=1e6+100;
char str[maxn],str1[maxn];
ll n,m;
bool judge(ll x){
for(int i=x,j=0;j<m;i++,j++){
if(i>=n)return false;
if(str[i]!=str1[j]){
return false;
}
}
return true;
}
int main(){
while(1){
cin>>str;
if(str[0]=='#'&&strlen(str)==1)break;
cin>>str1;
n=strlen(str);
m=strlen(str1);
ll res=0;
//cout<<n<<" "<<m<<endl;
for(int i=0;i<n;i++){
if(str[i]!=str1[0]){
continue;
}
//cout<<i<<endl;
if(judge(i)){
//cout<<i<<endl;
i=i+m-1;
res++;
}
//cout<<i<<endl;
}
printf("%lld\n",res);
}
return 0;
}
kmp代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long int ll;
const ll maxn=1e6+100;
ll nex[maxn];
char str[maxn],str1[maxn];
void getnex(char *str){
nex[0]=-1;
ll j=0,k=-1;
ll n=strlen(str);
while(j<n){
if(k==-1||(str[j]==str[k])){
j++;
k++;
nex[j]=k;
}else{
k=nex[k];//关键步骤
}
}
/*for(int i=0;i<n;i++){
cout<<nex[i]<<" ";
}
cout<<endl;*/
}
ll kmp(char *str,char *str1){
ll i=0,j=0;
ll mn=strlen(str);
ll n=strlen(str1);
//cout<<n<<endl;
ll res=0;
while(i<mn){
if((j==-1)||(str[i]==str1[j])){
i++;
j++;
if(j==n){
res++;
j=0;
}
}else{
j=nex[j];
}
//cout<<i<<" "<<j<<endl;
}
//cout<<j<<endl;
return res;
}
int main(){
while(1){
cin>>str;
if(str[0]=='#'&&strlen(str)==1){
break;
}
cin>>str1;
getnex(str1);
ll k=kmp(str,str1);
printf("%lld\n",k);
}
return 0;
}
L - 最长回文子串
思路:经典题目,用动态规划,其中是用已经确定的结果来进行推,第一层循环是倒着的,第二层是正的,原因是dp[i][j]的结果是从dp[i+1][j-1]推出的因此第一层是需要先推大的i值,第二层j需要的是小的j值
第一种情况 i==j时一定时回文串dp[i][i]=1
第二种情况 j-i<3是是临界情况,只要 str[i] == str[j],则 dp[i][j] 是回文子串(如"aa",“aba”),否则不是;
第三种情况当 j - i >= 3,如果 str[i] == str[j] && dp[i+1][j-1] ,则 dp[i][j] 是回文子串,否则不是 。
代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long int ll;
const ll maxn=1e6+100;
char str[maxn];
ll dp[1010][1010];
ll len=0;
int main(){
cin>>str+1;
ll n=strlen(str+1);
for(int i=1;i<=n;i++){
dp[i][i]=1;
}
for(int i=n;i>=1;i--){
for(int j=i+1;j<=n;j++){
if(str[i]==str[j]){
if(j-i<3){
dp[i][j]=1;
}else if(dp[i+1][j-1]){
dp[i][j]=1;
}
}
if(dp[i][j]){
len=max((ll)(j-i+1),len);
}
}
}
printf("%lld",len);
return 0;
}