PTA-21级数据结构与算法实验4——字符串和数组

目录

7-1 字符串模式匹配(KMP)

7-2 【模板】KMP字符串匹配

7-3 统计子串

7-4 好中缀

7-5 病毒变种

7-6 判断对称矩阵

7-7 三元组顺序表表示的稀疏矩阵转置运算Ⅰ

7-8 三元组顺序表表示的稀疏矩阵加法

7-9 三元组顺序表表示的稀疏矩阵转置Ⅱ

7-10 最大子矩阵和问题

7-1 字符串模式匹配(KMP)

给定一个字符串 text 和一个模式串 pattern,求 pattern 在text 中的出现次数。text 和 pattern 中的字符均为英语大写字母或小写字母。text中不同位置出现的pattern 可重叠。

输入格式:

输入共两行,分别是字符串text 和模式串pattern。

输出格式:

输出一个整数,表示 pattern 在 text 中的出现次数。

输入样例1:

zyzyzyz

zyz

输出样例1:

3

输入样例2:

AABAACAADAABAABA

AABA

输出样例2:

3

数据范围与提示:

1≤text, pattern 的长度 ≤106, text、pattern 仅包含大小写字母。

参考代码:运行环境C(gcc)

#include<stdio.h>
char t[1000001],p[1000001];
int next[1000001],con=0;
int lt,lp;
void get_next(){
	int i=-1,j=0;
	next[0]=-1;//这里由于一般下标从1开始但为了简便下标从零开始但赋值为-1
	while(j<lp){
		if(i==-1||p[j]==p[i]){
			i++;
			j++;
			next[j]=i;//第一次next[1]=0符合公式
		}
		else i=next[i];
	}
}
void kmp(){
	int i=0,j=0;
	while(i<lt){//并不是找第一次出现while条件减少主串完即可
		if(j==-1||t[i]==p[j]){
			i++;
			j++;
		}
		else j=next[j];
		if(j==lp)
		{
		    con++;
        }
	}
}
int main(){
	scanf("%s%s",t,p);
	lt=strlen(t);
	lp=strlen(p);//用lt和lp存数据元素长度为了调用循环中省去strlen()防止在循环中超时
	get_next();
	kmp();
	printf("%d",con);
	return 0;
}

7-2 【模板】KMP字符串匹配

给出两个字符串text和pattern,其中pattern为text的子串,求出pattern在text中所有出现的位置。

为了减少骗分的情况,接下来还要输出子串的前缀数组next。

输入格式:

第一行为一个字符串,即为text。

第二行为一个字符串,即为pattern。

输出格式:

若干行,每行包含一个整数,表示pattern在text中出现的位置。

接下来1行,包括length(pattern)个整数,表示前缀数组next[i]的值,数据间以一个空格分隔,行尾无多余空格。

输入样例:

ABABABC

ABA

输出样例:

1

3

0 0 1

样例说明:

76a5b773ac72a089742d7385ffd99a7d.jpeg

参考代码:运行环境C(gcc)

#include<stdio.h>
#include<string.h>
char t[1000001],p[1000001];
int next[1000001];
int lt,lp;
void get_next()
{
    int i=0,j=-1;
    next[0]=-1;
    while(i<lp)
    {
        if(j==-1||p[j]==p[i])
        {
            i++;
            j++;
            next[i]=j;
        }
        else j=next[j];
    }
}
int kmp()
{
    int i=0,j=0;
    while(i<lt)
    {
        if(j==-1||t[i] == p[j])
        {
            i++;
            j++;
        }
        else j=next[j];
        if(j==lp)
        {
            printf("%d\n",i-j+1);//输出字串在主串匹配的位置
            j=next[j];//下个匹配开始
        }
    }
}

int main()
{
    int i;
    scanf("%s%s",t,p);
    lt=strlen(t);
    lp=strlen(p);//循环中调用strlen会占用很多运行时长
    get_next();
    kmp();
    for(i=1;i<lp; i++)
    {
        printf("%d ",next[i]);
    }
    printf("%d\n",next[i]);
    return 0;
}

7-3 统计子串

编写算法,统计子串t在主串s中出现的次数。

输入格式:

首先输入一个整数T,表示测试数据的组数,然后是T组测试数据。每组测试数据在第一行中输入主串s,在第二行中输入子串t,s和t中不包含空格。

输出格式:

对于每组测试,若子串t在主串s中出现,则输出t在s中的子串位置和出现总次数,否则输出“0 0”。引号不必输出。

输入样例:

2

abbbbcdebb

bb

abcde

bb

输出样例:

2 4

0 0

参考代码:运行环境C(gcc)

#include<stdio.h>
#include<string.h>
int main()
{
    int T;
    scanf("%d",&T);
    while(T--){
        char s[100001],t[100],a[100];
        scanf("%s%s",s,t);
        int i,j,lt=strlen(t),con=0,flag=-1;
        for(i=0;s[i]!='\0';i++){//优化的BF算法
            for(j=0;j<lt;j++){
                a[j]=s[i+j];
            }
            a[lt]='\0';
            if(strcmp(a,t)==0&&flag==-1)flag=i+1;
            if(strcmp(a,t)==0)con++;
        }
        if(flag!=-1)printf("%d %d\n",flag,con);
        else printf("0 0\n");
    }
    return 0;
}

7-4 好中缀

作者 朱允刚

单位 吉林大学

我们称一个字符串S的子串T为好中缀,如果T是去除S中满足如下条件的两个子串p和q后剩余的字符串。

(1)p是S的前缀,q是S的后缀;

(2)p=q;

(3)p和q是满足条件(1)(2)的所有子串中的第二长者。

注意一个字符串不能称为自己的前缀或后缀。好中缀至少为空串,其长度大于等于0,不能为负数。

输入格式:

输入为一个字符串S,包含不超过100000个字母。

输出格式:

输出为一个整数,表示好中缀的长度。

输入样例1:

abcabcxxxabcabc

输出样例1:

9

输入样例2:

xacbacba

输出样例2:

8

输入样例3:

aaa

输出样例3:

1

参考代码:(C环境)

#include<stdio.h>
#include<string.h>
int main()
{
    char s[100001];
    scanf("%s",s+1);
    int ls=strlen(s+1),next[100001],i=1,j=0;next[1]=0;
    while(i<ls)
    {
        if(j==0||s[i]==s[j])next[++i]=++j;
        else j=next[j];
    }//next算法
    int x=ls-2*next[next[ls]];//next[next[ls]]就是第二长子串的长度
    if(x>=0)printf("%d",x);
    else printf("0");
    return 0;
}

7-5 病毒变种

作者 王东

单位 贵州师范学院

病毒DNA可以表示成由一些字母组成的字符串序列,且病毒的DNA序列是环状的。例如,假设病毒的DNA序列为baa,则该病毒的DNA序列有三种变种:baa,aab,aba。试编写一程序,对给定的病毒DNA序列,输出该病毒所有可能的DNA序列(假设变种不会重复)。

输入格式:

输入第一行中给出1个整数i(1≤i≤11),表示待检测的病毒DNA。 输入i行串序列,每行一个字符串,代表病毒的DNA序列,病毒的DNA序列长度不超过500。

输出格式:

依次逐行输出每个病毒DNA所有变种,各变种之间用空格分隔。

输入样例1:

1

baa

输出样例1:

baa aab aba

输入样例2:

2

abc

baac

输出样例2:

abc bca cab

baac aacb acba cbaa

参考代码:C语言(gcc)

#include <stdio.h>
#include <string.h>
int main()
{
    int n;
    scanf("%d",&n);
    while(n--){
        char s[501];
        scanf("%s",s);
        int ls=strlen(s),i,j;
        printf("%s ",s);//环状病毒有ls种
        for(i=2;i<=ls;i++){//第一种直接输出了这里是剩余的
            s[ls]=s[0];//剩下几种是左移
            for(j=1;j<=ls;j++){
                s[j-1]=s[j];
            }s[j-1]='\0';
            printf("%s ",s);
        }
        printf("\n");
    }
    return 0;
}

7-6 判断对称矩阵

作者 张德荣

单位 浙大宁波理工学院

将矩阵的行列互换得到的新矩阵称为转置矩阵。

m×n矩阵
A=⎣⎡​a11​a21​⋅⋅⋅am1​​a12​a22​⋅⋅⋅am2​​⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅​a1na2n​⋅⋅⋅amn​​⎦⎤​
的行列互换之后得到的矩阵,称为 A 的转置矩阵,记作 AT ,

AT=⎣⎡​a11​a12​⋅⋅⋅a1n​​a21​a22​⋅⋅⋅a2n​​⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅​am1​am2​⋅⋅⋅amn​​⎦⎤​

由定义可知, A 为m×n 矩阵,则 AT 为 n×m 矩阵。例如,
A=[1−2​01​23​]
,
AT=⎣⎡​102​−213​⎦⎤​.
n×n矩阵称之为 n阶方阵,

如果 n 阶方阵和它的转置相等,即 AT=A ,则称矩阵 A 为对称矩阵。

输入格式:

在第一行内给出n值(1<n<100)。

从第二行以后给出n阶矩阵所有行的元素值。

输出格式:

当输入的n阶矩阵是对称矩阵,输出“Yes”,否则输出“No”。

输入样例:

3

1 0 2

-2 1 3

4 3 2

输出样例:

No

输入样例:

3

1 -2 4

-2 1 3

4 3 2

输出样例:

Yes

参考代码:C语言(gcc)

#include<stdio.h>
int main()
{
	int a[100][100],flag=0,i,j,n;
	scanf("%d",&n);
	for(i=0;i<n;i++){
        for(j=0;j<n;j++){
            scanf("%d",&a[i][j]);
        }
    }
	for(i=0;i<n;i++){
		for(j=0;j<n;j++){
			if(a[i][j]!=a[j][i])
			flag=1;
			break;
	    }
    }
	if(flag==0)printf("Yes");
	else printf("No");				
	return 0;
}

7-7 三元组顺序表表示的稀疏矩阵转置运算Ⅰ

作者 王东

单位 贵州师范学院

三元组顺序表表示的稀疏矩阵转置。

输入格式:

输入第1行为矩阵行数m、列数n及非零元素个数t。
按行优先顺序依次输入t行,每行3个数,分别表示非零元素的行标、列标和值。

输出格式:

输出转置后的三元组顺序表结果,每行输出非零元素的行标、列标和值,行标、列标和值之间用空格分隔,共t行。

输入样例1:

3 4 3

0 1 -5

1 0 1

2 2 2

输出样例1:

0 1 1

1 0 -5

2 2 2

参考代码(gcc)

#include<stdio.h>
typedef struct{
int i,j,e;//行下标、列下标、值
}Triple;
typedef struct{
Triple data[1000];
int li,lj,le;
}TSMatrix;
int main()
{
TSMatrix a,b;
int i,j,k=0,m,n,t;//输入的行数、列数、非零的个数
scanf("%d%d%d",&m,&n,&t);
a.li=m;a.lj=n;a.le=t;//行、列、非零元素的个数
for(i=0;i<t;i++){
scanf("%d%d%d",&a.data[i].i,&a.data[i].j,&a.data[i].e);
}
b.li=a.lj,b.lj=a.li,b.le=a.le;
for(i=0;i<a.lj;i++){
    for(j=0;j<a.le;j++){
    if(a.data[j].j==i){
    b.data[k].i=a.data[j].j;
    b.data[k].j=a.data[j].i;
    b.data[k].e=a.data[j].e;
   k++;
    }
   }
 }
for(i=0;i<t;i++)
printf("%d %d %d\n",b.data[i].i,b.data[i].j,b.data[i].e);
}

7-8 三元组顺序表表示的稀疏矩阵加法

作者 王东

单位 贵州师范学院

三元组顺序表表示的稀疏矩阵加法。

输入格式:

输入第1行为两个同型矩阵的行数m、列数n,矩阵A的非零元素个数t1,矩阵B的非零元素个数t2。
按行优先顺序依次输入矩阵A三元组数据,共t1行,每行3个数,分别表示非零元素的行标、列标和值。
按行优先顺序依次输入矩阵B三元组数据,共t2行,每行3个数,分别表示非零元素的行标、列标和值。

输出格式:

输出第1行为相加后矩阵行数m、列数n及非零元素个数t。
输出t行相加后的三元组顺序表结果,每行输出非零元素的行标、列标和值,每行数据之间用空格分隔。

输入样例1:

4 4 3 4

0 1 -5

1 3 1

2 2 1

0 1 3

1 3 -1

3 0 5

3 3 7

输出样例1:

4 4 4

0 1 -2

2 2 1

3 0 5

3 3 7

参考代码:C语言(gcc)

#include<stdio.h>
typedef struct{
   int i,j,e;
}Triple;
typedef struct{
    Triple data[100];
    int li,lj,le;
}TSMatrix;
int main()
{
    TSMatrix a,b,c;
    scanf("%d%d%d%d",&a.li,&a.lj,&a.le,&b.le);
    b.li=a.li,b.lj=b.lj;
    int i,j,t;
    for(i=0;i<a.le;i++)
    scanf("%d%d%d",&a.data[i].i,&a.data[i].j,&a.data[i].e);
    for(i=0;i<b.le;i++)
    scanf("%d%d%d",&b.data[i].i,&b.data[i].j,&b.data[i].e);
    t=0,i=0,j=0;
    while(i<a.le&&j<b.le)
    {
        if(a.data[i].i<b.data[j].i)c.data[t++]=a.data[i++];
        else if(a.data[i].i>b.data[j].i)c.data[t++]=b.data[j++];
        else if(a.data[i].j<b.data[j].j)c.data[t++]=a.data[i++];
        else if(a.data[i].j>b.data[j].j)c.data[t++]=b.data[j++];
        else{//行相等且列相等
            a.data[i].e+=b.data[j].e;
            if(a.data[i].e)c.data[t++]=a.data[i];//记录非零元素值
            i++,j++;//查询的a,b的元素值都要往后移
        }
    }//剩余数据元素直接录入
    for(;i<a.le;i++)
    c.data[t++]=a.data[i];
    for(;j<b.le;j++)
    c.data[t++]=b.data[j];
    printf("%d %d %d\n",a.li,a.lj,t);
    for(i=0;i<t;i++)
    printf("%d %d %d\n",c.data[i].i,c.data[i].j,c.data[i].e);
    return 0;
}

7-9 三元组顺序表表示的稀疏矩阵转置Ⅱ

作者 王东

单位 贵州师范学院

三元组顺序表表示的稀疏矩阵转置Ⅱ。设a和b为三元组顺序表变量,分别表示矩阵M和T。要求按照a中三元组的次序进行转置,并将转置后的三元组置入b中恰当的位置。

输入格式:

输入第1行为矩阵行数m、列数n及非零元素个数t。
按行优先顺序依次输入t行,每行3个数,分别表示非零元素的行标、列标和值。

输出格式:

按置入b中的顺序输出置入的位置下标,转置后的三元组行标、列标和值,数据之间用空格分隔,共t行。

输入样例1:

3 4 3

0 1 -5

1 0 1

2 2 2

输出样例1:

1 1 0 -5

0 0 1 1

2 2 2 2

参考代码,C语言(gcc)

#include<stdio.h>
typedef struct {
    int i,j,e,x;//多一个x是置入位置下标
}Triple;
typedef struct {
    Triple data[101];
    int li,lj,le;
}TSMatrix;
int main() {
    TSMatrix a,b;
    scanf("%d%d%d",&a.li,&a.lj,&a.le);
    int i,j,p,q,col,t;
    for(i=0;i<a.le;i++)
    scanf("%d%d%d",&a.data[i].i,&a.data[i].j,&a.data[i].e);
    b.li=a.lj,b.lj=a.li,b.le=a.le;//矩阵转置
    if(b.le){
        q=0;//q是存转置矩阵的下标
        for(col=0;col<a.lj;col++)
        for(p=0;p<a.le;p++)
        if(a.data[p].j==col){//x是下标置入b的顺序
            b.data[q].x=q;
            b.data[q].i=a.data[p].j,b.data[q].j=a.data[p].i;
            b.data[q].e=a.data[p].e,q++;//行列互换,值相等,下标自增1
        }
    }//按置入b的顺序即按行优先输出
     for(i=0;i<b.le;i++){
        t=a.data[i].e;
        for(j=0;j<b.le;j++)
        if(t==b.data[j].e)printf("%d %d %d %d\n",b.data[j].x,b.data[j].i,b.data[j].j,b.data[j].e);
     }
    return 0;
}

7-10 最大子矩阵和问题

作者 王东

单位 贵州师范学院

最大子矩阵和问题。给定m行n列的整数矩阵A,求矩阵A的一个子矩阵,使其元素之和最大。

输入格式:

第一行输入矩阵行数m和列数n(1≤m≤100,1≤n≤100),再依次输入m×n个整数。

输出格式:

输出第一行为最大子矩阵各元素之和,第二行为子矩阵在整个矩阵中行序号范围与列序号范围。

输入样例1:

5 6

60 3 -65 -92 32 -70

-41 14 -38 54 2 29

69 88 54 -77 -46 -49

97 -32 44 29 60 64

49 -48 -96 59 -52 25

输出样例1:

输出第一行321表示子矩阵各元素之和,输出第二行2 4 1 6表示子矩阵的行序号从2到4,列序号从1到6

321

2 4 1 6

参考代码:C语言(gcc环境)

#include<stdio.h>
int main(){
int sum[1001][1001];
int m,n,i,j,k,max=0,now,a,x1,x2,y1,y2;
    scanf("%d%d",&m,&n);
    for(i=1;i<=m;i++)//由于涉及序号范围以1为起点
        for(j=1;j<=n;j++){
            scanf("%d",&a);
            sum[i][j]=sum[i-1][j]+a;//记录矩阵目前一列和
        }
    for(i=1;i<=m;i++)//用于控制子矩阵的下边界
        for(j=1;j<=i;j++){//用于控制子矩阵的上边界
            now=0;
            int y=1;
            for(k=1;k<=n;k++){//用于控制子矩阵的右边界
                now+=sum[i][k]-sum[j-1][k];//动态规划原理参考网站1。
                if(now>max){//与最大子列和原理类似
                    max=now;
                    x2=i;
                    y2=k;
                    x1=j;
                    y1=y;//记录每次行和列的范围
                }
                if(now<0){
                    now=0;
                    y=k+1;
                }
            }
        }
    printf("%d\n%d %d %d %d",max,x1,x2,y1,y2);
}

动态规划:最大子矩阵 - Alinshans - 博客园 (cnblogs.com)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

救救孩子√

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值