【寒假训练/Java】字符串专题

题目链接

字符串专题-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)

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;
            }
        }
    }
}
  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值