文章目录
题目链接
字符串专题-Vjudge链接
比赛密码:202301032000
题目列表
A - 首字母大写
import java.io.*;
import java.util.*;
public class Main {
public static void main(String[] args) {
Scanner sc=new Scanner(System.in);
while (sc.hasNext()) {
char[] str=sc.nextLine().toCharArray();
for (int i=0;i<str.length;i++) {
if (i==0&&str[i]>='a'&&str[i]<='z') str[i]-=32;
else if (str[i]=='\t'||str[i]==' '||str[i]=='\r'||str[i]=='\n') {
if (str[i+1]>='a'&&str[i+1]<='z')str[i+1]-=32;
}
System.out.print(str[i]);
}
}
}
}
B - 验证子串
import java.io.*;
import java.util.*;
public class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
String s1=sc.next(),s2=sc.next();
if(s1.contains(s2)){
System.out.printf("%s is substring of %s\n",s2,s1);
}else if(s2.contains(s1)){
System.out.printf("%s is substring of %s\n",s1,s2);
}else{
System.out.println("No substring");
}
}
}
C - 大小写转换
import java.io.*;
import java.util.*;
public class Main {
public static void main(String[] args) {
Scanner sc=new Scanner(System.in);
while (sc.hasNext()) {
char[] str=sc.nextLine().toCharArray();
for (int i=0;i<str.length;i++) {
if (str[i]>='a'&&str[i]<='z') str[i]-=32;
System.out.print(str[i]);
}
System.out.println();
}
}
}
D - Text Reverse
PE可能原因,单词间可能有多个空格,直接将行字符串以空格分割再翻转输出,可能导致输出格式不正确。
import java.io.*;
import java.util.*;
public class Main {
public static void main(String[] args) {
Scanner sc=new Scanner(System.in);
int T=sc.nextInt();
sc.nextLine();
StringBuilder s1,s2;
boolean f=true;//判断是否为连续空格
while (T-->0) {
char[] c=sc.nextLine().toCharArray();
s1=new StringBuilder();
s2=new StringBuilder();
for (int i=0;i<c.length;i++) {
if(c[i]!=' '){
if(!f)f=true;
s2.append(c[i]);
if(i==c.length-1){
s2=s2.reverse();
s1.append(s2);
s2=new StringBuilder();
}
}else{
if(f){//该字符为空格,上一个字符为单词结尾
f=false;
s2=s2.reverse();
s1.append(s2).append(" ");
s2=new StringBuilder();
}else{//该字符为连续空格
s1.append(" ");
}
}
}
System.out.println(s1);
}
}
}
E - 排序
import java.io.*;
import java.util.*;
public class Main {
public static void main(String[] args) {
Scanner sc=new Scanner(System.in);
while(sc.hasNext()){
String val=sc.next(),s;
int num;
StringTokenizer str=new StringTokenizer(val,"5");
ArrayList<Integer> ls=new ArrayList<>();
while(str.hasMoreTokens()){
s=str.nextToken();
num=Integer.parseInt(s);
ls.add(num);
}
Collections.sort(ls);
boolean f=false;//第一个数字前没有空格
for(int i:ls) {
if(!f)f=true;
else System.out.print(" ");
System.out.print(i);
}
System.out.println();
}
}
}
F - What Are You Talking About(字典树)
Map解法
import java.io.*;
import java.util.*;
public class Main {
public static void main(String[] args) {
Scanner sc=new Scanner(System.in);
boolean f=false;
Map<String,String> mp=new HashMap<>();
while (sc.hasNext()) {
String s=sc.nextLine();
if(s.equals("START"))continue;
if(s.equals("END")){
if(!f){
f=true;
continue;
}else break;
}
if(!f){
String[] ss=s.split(" ");
mp.put(ss[1],ss[0]);
}else{
char[] str=s.toCharArray();
StringBuilder sb1=new StringBuilder(),sb2=new StringBuilder();
for(int i=0;i<str.length;i++){
if(str[i]=='\t'||str[i]==' '||str[i]=='\r'||str[i]=='\n'||!(str[i]>='a'&&str[i]<='z')){
sb1.append(mp.getOrDefault(sb2.toString(),sb2.toString()));
sb1.append(str[i]);
sb2=new StringBuilder();
}else{
sb2.append(str[i]);
if(i==str.length-1){
sb1.append(mp.getOrDefault(sb2.toString(),sb2.toString()));
sb2=new StringBuilder();
}
}
}
System.out.println(sb1);
}
}
}
}
字典树解法-查找速度更快
字典树(Java版)
C++版本
#include<bits/stdc++.h>
using namespace std;
int t=0;
string x,x1;
struct trie{
int son[26];
int flag;
string xx;
}a[1000050];
void add(){
int i,l=x.length(),p=0;
for(i=0;i<l;i++){
if(a[p].son[x[i]-'a']==0)
a[p].son[x[i]-'a']=++t;
p=a[p].son[x[i]-'a'];
}
a[p].xx=x1;
a[p].flag=1;
}
string find(){
int i,l=x.length(),p=0;
l=x.length();
for(i=0;i<l;++i){
if(a[p].son[x[i]-'a']==0)
return x;
p=a[p].son[x[i]-'a'];
}
if(a[p].flag==1) return a[p].xx;
else return x;
}
int main(){
cin>>x;//START
while(cin>>x1>>x){
if(x1=="END")break;//此时x为翻译部分的START
add();
}
char c;
c=getchar();//读取上一次输入的结束符
x="";
while(1){
while(1){
scanf("%c",&c);
//输入内容均为小写,判断是否为大写是为了防止读取结束标志 END
if(!((c>='a'&&c<='z')||(c>='A'&&c<='Z')))break;
x+=c;
}
if(x=="END")break;
cout<<find();
x="";
printf("%c",c);
}
}
Java版测试的几次都是MLE,把代码贴在这,有待改进
import java.io.*;
import java.util.*;
public class Main {
static int t=0;
static char[] x;
static String x1;
static ArrayList<trie> a=new ArrayList<>();
public static void main(String[] args) {
Scanner sc=new Scanner(System.in);
boolean f=false;
while (sc.hasNext()) {
String s=sc.nextLine();
if(s.equals("START"))continue;
if(s.equals("END")){
if(!f){
f=true;
continue;
}else break;
}
//字典内容输入,构建字典树
if(!f){
String[] ss=s.split(" ");
x1=ss[0];//第一个单词-英文
x=ss[1].toCharArray();//第二个单词-火星文
add();
}else{
char[] str=s.toCharArray();
StringBuilder sb=new StringBuilder();
for(int i=0;i<str.length;i++){
if(str[i]=='\t'||str[i]==' '||str[i]=='\r'||str[i]=='\n'||!(str[i]>='a'&&str[i]<='z')){
x=sb.toString().toCharArray();
System.out.print(find());
System.out.print(str[i]);
sb=new StringBuilder();
}else{
sb.append(str[i]);
if(i==str.length-1){
x=sb.toString().toCharArray();
System.out.print(find());
sb=new StringBuilder();
}
}
}
System.out.println();
}
}
}
static void add(){
int p=0;
for(int i=0;i<x.length;i++){
if(a.size()<=p)a.add(new trie());
if(a.get(p).son[x[i]-'a']==0)
a.get(p).son[x[i]-'a']=++t;
p=a.get(p).son[x[i]-'a'];
}
if(a.size()<=p)a.add(new trie());
a.get(p).xx=x1;
a.get(p).flag=1;
}
static String find(){
int p=0;
for(int i=0;i<x.length;i++){
if(a.get(p).son[x[i]-'a']==0)
return String.valueOf(x);//字典树中不存在,直接返回火星文
p=a.get(p).son[x[i]-'a'];
}
if(a.get(p).flag==1) return a.get(p).xx;//字典树中存在,返回对应的英文
else return String.valueOf(x);
}
}
class trie {
int[] son;
int flag;
String xx;
public trie(){
son=new int[26];
flag=0;
}
}
G - AC Me
import java.io.*;
import java.util.*;
public class Main {
static int[] a;
public static void main(String[] args) {
Scanner sc=new Scanner(System.in);
char[] c;
while(sc.hasNext()){
a=new int[26];
c=sc.nextLine().toCharArray();
for(int i=0;i<c.length;i++){
if(c[i]>='a'&&c[i]<='z'){
a[c[i]-'a']++;
}
}
print();
}
}
public static void print(){
for(int i=97;i<=122;i++){
System.out.println((char)i+":"+a[i-97]);
}
System.out.println();
}
}
H - 剪花布条(kmp)
第一版:kmp解法
从头到尾彻底理解KMP
【Java/板子】kmp
import java.io.*;
import java.util.*;
public class Main {
public static void main(String[] args) {
Scanner sc=new Scanner(System.in);
while (sc.hasNext()) {
String s1 = sc.next();
if (s1.equals("#")) {
break;
}
char[] a=s1.toCharArray(), b=sc.next().toCharArray();
kmp(a, b);
}
}
public static void getnext(char[] b,int[] next){
int j=0,k=-1;
next[0]=-1;
while(j<b.length-1){
if(k==-1||b[j]==b[k]){
j++;k++;
//查找区域不能重叠
if(b[j]!=b[k])next[j]=k;
else next[j]=next[k];
}else k=next[k];
}
}
public static void kmp(char[] a,char[] b) {
int next[]=new int[b.length],i=0,j=0;
getnext(b,next);
int ans=0;
while (i<a.length&&j<b.length) {
if (j==-1||a[i]==b[j]) {
i++;j++;
} else j=next[j];
if(j==b.length){
i--;j--;
ans++;
j=next[j];
}
}
System.out.println(ans);
}
}
第二版:循环解法
import java.io.*;
import java.util.*;
public class Main {
public static void main(String[] args) {
Scanner sc=new Scanner(System.in);
while (sc.hasNext()){
String s1=sc.next();
if (s1.equals("#"))break;
char[] ch1=s1.toCharArray(),ch2=sc.next().toCharArray();
int ans=0,k;
if (ch1.length<ch2.length){
System.out.println("0");
}else{
for (int i=0;i<ch1.length;i++){
k=0;
for (int j=0;(i+j)<ch1.length&&j<ch2.length;j++){
if (ch1[i+j]==ch2[j]){
k++;
}else break;
if (k==ch2.length){
ans++;
i=i+k-1;
}
}
}
System.out.println(ans);
}
}
}
}
第三版:在第一个kmp解法的基础上改动了getnext()和kmp()两个函数的算法
◎getnext():查找区域有重叠。
比如zyzyz中找zyz,第二个zyz可以从主串中的第三个字符找起。
◎kmp算法:匹配到一次子串,主串指针位置后移,子串指针位置回溯
import java.io.*;
import java.util.*;
public class Main {
public static void main(String[] args) {
Scanner sc=new Scanner(System.in);
while (sc.hasNext()) {
String s1 = sc.next();
if (s1.equals("#")) {
break;
}
char[] a=s1.toCharArray(), b=sc.next().toCharArray();
kmp(a,b);
}
}
public static void getnext(char[] b,int[] next){
int j=0,k=-1;
next[0]=-1;
while(j<b.length-1){
if(k==-1||b[j]==b[k]){
j++;k++;
next[j]=k;//next[j]是j-1串的最长前后缀。
}else k=next[k];//递归,在最长前后缀中间继续寻找。
}
}
public static void kmp(char[] a,char[] b) {
int next[]=new int[b.length],i=0,j=0;
getnext(b,next);
int ans=0;
while (i<a.length) {
while(j>0&&a[i]!=b[j]){
j=next[j];
}//第一次位置
if(a[i]==b[j])j++;
if(j==b.length){
ans++;
j=0;//让模式串从头开始找。
}
i++;
}
System.out.println(ans);
}
}
三版解法耗时与消耗内存对比
I - 子串查找(kmp)
kmp模板题
import java.io.*;
import java.util.*;
public class Main {
public static void main(String[] args) {
Scanner sc=new Scanner(System.in);
char[] a=sc.next().toCharArray(),b=sc.next().toCharArray();
kmp(a,b);
}
public static void getnext(char[] b, int[] next) {
int j=0,k=-1;
next[0]=-1;
while(j<b.length-1){
if(k==-1||b[j]==b[k]){
j++;k++;
//因为A中不同位置出现的B可重叠,不能用kmp优化
next[j]=k;
}else k=next[k];
}
}
public static void kmp(char[] a,char[] b) {
int next[]=new int[b.length],i=0,j=0;
getnext(b,next);
int ans=0;
while (i<a.length&&j<b.length) {
if (j==-1||a[i]==b[j]) {
i++;j++;
} else j=next[j];
if(j==b.length){
i--;j--;
ans++;
j=next[j];
}
}
System.out.println(ans);
}
}
J - 字符串最大跨距
import java.io.*;
import java.util.*;
public class Main {
public static void main(String[] args) {
Scanner sc=new Scanner(System.in);
String[] s0=sc.nextLine().split(",");
String s=s0[0],s1=s0[1],s2=s0[2];
int idx1=s.indexOf(s1),idx2=s.lastIndexOf(s2),l=s1.length();
if(idx1+l>idx2||idx1==-1||idx2==-1) System.out.println(-1);
else System.out.println(idx2-idx1-l);
}
}
K - Cyclic Nacklace(kmp)
题意:给出一个字符串,问在末尾最少添加多少字符,使字符串至少循环两次。
解法:kmp求补齐循环节最小长度问题
C++版
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=1e5+5;
char s[N];
int Next[N];
//求next数组
//next数组的值是代表着字符串的前缀与后缀相同的最大长度
void getnext() {
Next[0]=-1;
int k=-1,i=0;
int len=strlen(s);
while(i<len) {
if(k==-1||s[k]==s[i]) {
k++;i++;
Next[i]=k;
}
else k=Next[k];
}
}
int main() {
int T;scanf("%d",&T);
while(T--){
scanf("%s",&s);
memset(Next,0,sizeof Next);
getnext();
int len=strlen(s);
int ans=len-Next[len];//即循环节长度
//循环节长度不等于字符串长度,并且字符串长度是循环节长度的倍数
if(ans!=len&&len%ans==0) printf("0\n");//字符串是循环的
else printf("%d\n",ans-Next[len]%ans);//除去与前缀相同的后缀,非循环的部分即为所求
}
}
Java版,与C++相同的方法一直WA,贴这里待改
import java.util.*;
import java.io.*;
public class Main {
static char[] s;
static int[] Next;
public static void main(String[] args) {
Scanner sc=new Scanner(System.in);
int T=sc.nextInt();
sc.nextLine();
while(T-->0){
s=sc.next().toCharArray();
Next=new int[100005];
getnext();
int len=s.length;
int ans=len-Next[len];
if(ans!=len&&len%ans==0) System.out.println("0");
else System.out.println(ans-Next[len]%ans);
}
}
static void getnext() {
Next[0]=-1;
int k=-1,i=0;
int len=s.length;
while(i<len) {
if(k==-1||s[k]==s[i]) {
k++;i++;
Next[i]=k;
}
else k=Next[k];
}
}
}
L - 最长回文(Manacher)
import java.util.*;
import java.io.*;
public class Main {
static int N=110010;
static char[] Ma=new char[N<<1],s;//转换后的字符串 & 原字符串
static int[] Len=new int[N<<1];
public static void main(String[] args) {
Scanner sc=new Scanner(System.in);
while(sc.hasNext()) {
s=sc.next().toCharArray();
int len=s.length;
Manacher(len);
int ans=0;
for(int i=0; i<2*len+2; i++)
//返回Len[i]中的最大值-1即为原串的最长回文子串额长度
ans=Math.max(ans,Len[i]-1);
System.out.println(ans);
}
}
static void Manacher(int len) {
//转换原始串
int l=0;
Ma[l++]='$';//为了避免更新P的时候导致越界而在字符串T的前增加一个特殊字符
Ma[l++]='#';
for(int i=0;i<len;i++) {
Ma[l++]=s[i];
Ma[l++]='#';
}
Ma[l]=0;//字符串结尾加一个特殊字符,注意与开始字符不同
//Manacher算法计算过程
int mx=0,po=0;//mx即为当前计算回文串最右边字符的最大值,po为 mx对应回文串的中心位置
//l = 2 * s.length + 3
for(int i=0;i<l;i++) {
/**
* mx>i : 在Len[j]和mx-i中取较小值
* mx<=i : 要从头开始匹配
*/
Len[i]=mx>i?Math.min(Len[2*po-i],mx-i):1;
while(i-Len[i]>=0&&Ma[i+Len[i]]==Ma[i-Len[i]])Len[i]++;
if(i+Len[i]>mx) {//若新计算的回文串右端点位置大于mx,要更新po和mx的值
mx=i+Len[i];
po=i;
}
}
}
}