PTA-数据结构字符串与数组|C语言版

目录

1、 字符串模式匹配(KMP)

2、 【模板】KMP字符串匹配

3、 统计子串

4、 好中缀

5、 病毒变种

6、 判断对称矩阵

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

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

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

10、 最大子矩阵和问题


1、 字符串模式匹配(KMP)

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

输入格式:

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

输出格式:

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

输入样例1:

zyzyzyz
zyz

输出样例1:

3

输入样例2:

AABAACAADAABAABA
AABA

输出样例2:

3
#include<stdio.h>
#include<string.h>
char pattern[1000000],text[1000000];
int n=0,m=0;
int next[1000000];
void next_pattern()
{
    int i=0,j=-1;
    next[0]=-1;
    while(i<m)
    {
        if(j==-1||pattern[i]==pattern[j])
        {
            i++;
            j++;
            next[i]=j;
        }
        else j=next[j];
    }
}
int kmp()
{
    int count=0,i=0,j=0;
    while(i<n)
    {
        while(i<n&&j<m)
        {
            if(j==-1||pattern[j]==text[i])
            {
                i++;
                j++;
            }
            else j=next[j];
        }
        if(j==m)
        {
        
            count++;
            i--;
            j=next[j-1];
        }
    }
    return count;
}
int main()
{
    while((text[n]=getchar())!='\n')n++;
    while((pattern[m]=getchar())!='\n')
        m++;
    next_pattern();
    int count=kmp();
    printf("%d",count);
    return 0;
}

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

样例说明:

#include<stdio.h>
#include<string.h>
int n=0,m=0,next[1000000];
char pattern[1000000],text[1000000];
void next_pattern()
{
    int i=0,j=-1;
    next[0]=-1;
    while(i<m)
    {
        if(j==-1||pattern[i]==pattern[j])
        {
            i++;
            j++;
            next[i]=j;
        }
        else j=next[j];
    }
}
void kmp()
{
    int i=0,j=0;
    while(i<n)
    {
        if(j==-1||text[i]==pattern[j])
        {
            i++;
            j++;
        }
        else j=next[j];
        if(j==m)
            printf("%d\n",i-m+1);
    }
}
int main()
{
    int i;
    while((text[n]=getchar())!='\n')
        n++;
    while((pattern[m]=getchar())!='\n')
        m++;
    next_pattern();
    kmp();
    for(i=1;i<m;i++)
        printf("%d ",next[i]);
    printf("%d",next[m]);
}

3、 统计子串

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

输入格式:

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

输出格式:

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

输入样例:

2
abbbbcdebb
bb
abcde
bb

输出样例:

2 4
0 0
#include<stdio.h>
#include<string.h>
void next_pattern(int m,char pattern[],int next[])
{
    int i=0,j=-1;
    next[0]=-1;
    while(i<m)
    {
        if(j==-1||pattern[i]==pattern[j])
        {
            i++;
            j++;
            next[i]=j;
        }
        else j=next[j];
    }
}
int kmp(int n,int m,int next[],char pattern[],char text[])
{
    int count=0,i=0,j=0,p=0;
    while(i<n)
    {
        if(pattern[j]==text[i]||j==-1)
        {
            i++;
            j++;
        }
        else j=next[j];
        if(j==m)
        {
            count++;
            if(p==0)
                printf("%d ",i-m+1);
            p++;
        }
    }
    if(count==0)
        printf("0 ");
    return count;
}
int main()
{
    int T;
    scanf("%d",&T);
    getchar();//换行符
    while(T--)
    {
        int n=0,m=0,next[1000000],count;
        char pattern[1000000],text[1000000];
        while((text[n]=getchar())!='\n')
            n++;
        while((pattern[m]=getchar())!='\n')
            m++;
        next_pattern(m,pattern,next);
        count=kmp(n,m,next,pattern,text);
        printf("%d\n",count);
    }
}

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

#include<stdio.h>
#include<string.h>
int next[1000000],n;
char text[1000000];
int next_text()
{
    int i=0,j=-1;
    next[0]=-1;
    while(i<n)
    {
        if(j==-1||text[i]==text[j])
        {
            i++;
            j++;
            next[i]=j;
        }
        else j=next[j];
    }
    return next[next[n]];
}
int main()
{
    scanf("%s",text);
    n=strlen(text);
    int k=next_text();
    if(2*k<n&&k>=0)
        printf("%d",n-2*k);
    else if(k==-1)//k=-1时,说明前缀和后缀都不相等,好中缀长度为字符串长度
        printf("%d",n);
    else printf("0");
}

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 

#include<stdio.h>
#include<string.h>
int T;
char dna[501];
int main()
{
    scanf("%d",&T);
    while(T--)
    {
        scanf("%s",dna);
        int t=strlen(dna);
        int k=t-1,i;
        //dna病毒为环状,一共有t种序列
        //先输出输入的dna病毒序列
        for(i=0;i<t-1;i++)
            printf("%c",dna[i]);
        printf("%c ",dna[t-1]);
        //再输出剩下的变异dna病毒序列
        while(k--)
        {
            //整个字符串向左移
            int p=dna[0];
            for(i=0;i<t-1;i++)
                dna[i]=dna[i+1];
            dna[t-1]=p;
            //输出变异的dna病毒序列
            for(i=0;i<t-1;i++)
                printf("%c",dna[i]);
            printf("%c ",dna[t-1]);
        }
        printf("\n");
    }
}

6、 判断对称矩阵

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

把m×n矩阵
A=⎣⎡​a11​a21​⋅⋅⋅am1​​a12​a22​⋅⋅⋅am2​​⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅​a1n​a2n​⋅⋅⋅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
#include<stdio.h>
int main()
{
    int n,a[101][101],i,j,flag=1;;
    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=0;
                break;
            }
        }
    if(flag==0)
        printf("No");
    else printf("Yes");
}

 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

#include<stdio.h>
 typedef struct
 {
     int i,j,num;
 }Num;
struct node
{
    int m,n,t;
    Num data[100000];
}T,S;
int main()
{
    int i,j,x=0;
    scanf("%d%d%d",&T.m,&T.n,&T.t);
    for(i=0;i<T.t;i++)
        scanf("%d%d%d",&T.data[i].i,&T.data[i].j,&T.data[i].num);
    S.m=T.n;
    S.n=T.m;
    S.t=T.t;
    for(i=0;i<T.n;i++)
    {
        for(j=0;j<T.t;j++)
        {
            if(i==T.data[j].j)
            {
                S.data[x].i=T.data[j].j;
                S.data[x].j=T.data[j].i;
                S.data[x].num=T.data[j].num;
                x++;
            }
        }
    }
    for(i=0;i<x;i++)
        printf("%d %d %d\n",S.data[i].i,S.data[i].j,S.data[i].num);
}

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

#include<stdio.h> 
typedef struct
{
    int i,j,num;//存储每个元素的行标、列标、值
}Num;
struct node
{
    int n,m,t;//矩阵的行数、列数、非零元素个数
    Num data[100000];
}T1,T2,S;//T1和T2为输入的两个稀疏矩阵
int main()
{
    scanf("%d%d%d%d",&T1.m,&T1.n,&T1.t,&T2.t);
    int i=0,j;
    for(i=0;i<T1.t;i++)
    {
        scanf("%d%d%d",&T1.data[i].i,&T1.data[i].j,&T1.data[i].num);
    }
    for(i=0;i<T2.t;i++)
    {
        scanf("%d%d%d",&T2.data[i].i,&T2.data[i].j,&T2.data[i].num);
    }
    int x=0;
    i=0,j=0;
    while(i<T1.t&&j<T2.t)
    {
        if(T1.data[i].i==T2.data[j].i&&T1.data[i].j==T2.data[j].j)//当两个矩阵在同一位置都存在值时
        {
            S.data[x].i=T1.data[i].i;
            S.data[x].j=T1.data[i].j;
            S.data[x].num=T1.data[i].num+T2.data[j].num;
            x++;
            if(S.data[x-1].num==0)//如果在该点的和为0,则要去掉该点
                x--;
            i++;
            j++;
        }
        //两稀疏矩阵为行优先输入
        //若T1和T2在同一行且T2的列标小,或者不在同一行且T2的行标小,则T2值直接赋值给S
        else if((T1.data[i].i==T2.data[j].i&&T1.data[i].j>T2.data[j].j)||T1.data[i].i>T2.data[j].i)
            S.data[x++]=T2.data[j++];
        //若T1和T2在同一行且T1的列标小,或者不在同一行且T1的行标小,则T1值直接赋值给S
        else if((T1.data[i].i==T2.data[j].i&&T1.data[i].j<T2.data[j].j)||T1.data[i].i<T2.data[j].i)
            S.data[x++]=T1.data[i++];
    }
    while(i<T1.t)//只剩下T1矩阵时
    {
        S.data[x++]=T1.data[i++];
    }
    while(j<T2.t)//只剩下T1=2矩阵时
    {
        S.data[x++]=T2.data[j++];
    }
    printf("%d %d %d\n",T1.m,T1.n,x);
    for(i=0;i<x;i++)
        printf("%d %d %d\n",S.data[i].i,S.data[i].j,S.data[i].num);
}

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

#include<stdio.h>
 typedef struct
 {
     int i,j,num,y;
 }Num;
struct node
{
    int m,n,t;
    Num data[100000];
}T,S;
int main()
{
    int i,j,x=0,y=0;
    scanf("%d%d%d",&T.m,&T.n,&T.t);
    for(i=0;i<T.t;i++)
        scanf("%d%d%d",&T.data[i].i,&T.data[i].j,&T.data[i].num);
    S.m=T.n;
    S.n=T.m;
    S.t=T.t;
    //进行稀疏矩阵的逆置
    for(i=0;i<T.n;i++)
    {
        for(j=0;j<T.t;j++)
        {
            if(i==T.data[j].j)
            {
                S.data[x].y=x;
                S.data[x].i=T.data[j].j;
                S.data[x].j=T.data[j].i;
                S.data[x].num=T.data[j].num;
                x++;
            }
        }
    }
    for(i=0;i<T.t;i++)
    {
        int k=T.data[i].num;//S按列优先顺序排序,T按行优先顺序排序
        //题目输出要求按行优先顺序排序
        for(j=0;j<T.t;j++)
        {
            if(S.data[j].num==k)
                printf("%d %d %d %d\n",S.data[j].y,S.data[j].i,S.data[j].j,S.data[j].num);
        }
    }
}

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
#include<stdio.h>
#define N 1001//若范围小的话会出现段错误
int sum[N][N];
int main()
{
    int n,m,i,j,num;
    scanf("%d%d",&m,&n);
    for(i=1;i<=m;i++)
        sum[i][0]=0;
    for(i=1;i<=m;i++)
        for(j=1;j<=n;j++)
        {
            scanf("%d",&num);
            sum[i][j]=sum[i][j-1]+num;
        }
    int t=-1,k=0;
    int left,right,x1=0,x2=0,y1=0,y2=0;
    for(left=1;left<=n;left++)//遍历求和的起始列
        for(right=left;right<=n;right++)//遍历求和的终止列
        {
            k=0;
            for(i=1;i<=m;i++)//行数
            {
                if(k<0)
                    k=0;
                k=k+sum[i][right]-sum[i][left-1];
                if(k>t)
                {
                    t=k;
                    y1=left;
                    y2=right;
                    x2=i;
                }
                
            }
        }
    for(i=1;i<=x2;i++)//遍历求和的起始行
    {
        k=0;
        for(j=i;j<=x2;j++)//遍历求和的终止行
            k=k+sum[j][y2]-sum[j][y1-1];
        if(k==t)
        {
            x1=i;
            break;
        }
    }
    printf("%d\n%d %d %d %d",t,x1,x2,y1,y2);
}
  • 1
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值