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

28 篇文章 2 订阅
14 篇文章 24 订阅

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 仅包含大小写字母。

#include<stdio.h>
#include<string.h>
int main()
{
    char s[1000010],p[1000010];
    int next[1000010];
    scanf("%s %s",s+1,p+1);
    int n=strlen(s+1),m=strlen(p+1);
    int j=0,i;
    for(i=2;i<=m;i++)//next数组记录
    {   //next[i]的值表示下标为i的字符串前的字符串的最长相等前后缀的长度
        //也表示该处字符不匹配时应该回溯到的字符的下标
        while(j&&p[i]!=p[j+1])
            j=next[j];
        if(p[i]==p[j+1])
            j++;
        next[i]=j;
    }
    int cot=0;
    j=0;
    for(i=1;i<=n;i++)
    {
        while(j&&s[i]!=p[j+1])
            j=next[j];
        if(s[i]==p[j+1])
            j++;//匹配成功,后移
        if(j==m)
        {
            cot++;
            j=next[j];//注意更新j
        }
    }
    printf("%d",cot);
    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

样例说明:

#include<string.h>
#include<stdio.h>
#define MAXN 1000010
int next[MAXN];
int s1,s2,j; 
char a[MAXN],b[MAXN],d;
int main()
{
    scanf("%s",a+1);
    scanf("%s",b+1);
    s1=strlen(a+1);
    s2=strlen(b+1);
    int i;
    for (i=2;i<=s2;i++)//建立next数组用于记录该位置前最长相等前后缀的组数;
    {
        while(j&&b[i]!=b[j+1])
        {
            j=next[j];
        }
        if(b[j+1]==b[i])
        {
            j++;
        }
        next[i]=j;
    }
    j=0;
    for(i=1;i<=s1;i++)
    {
        while(j&&b[j+1]!=a[i])
        {
            j=next[j];
        }
        if(b[j+1]==a[i])
        {
            j++;
        }
        if(j==s2)
        {
            printf("%d\n",i-s2+1);//输出出现的位置
            j=next[j];
        }
    }
    for(i=1;i<=s2-1;i++)
    {
        printf("%d ",next[i]);
    }
    printf("%d",next[s2]);//输出next数组记录的值;
    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
#include<stdio.h>
#include<string.h>
int nexts[100005];
void getNext(char str[])
{
	int m = strlen(str);
	int j=-1,i=0;
	nexts[0]=-1;
	while(i<m-1)
    {
		if(j==-1||str[i]==str[j])
        {
			i++;
			j++;
			nexts[i]=j;
		}
        else
        {
			j=nexts[j];
		}
	}
}
int main()
{
	int n;
	char a[100001],b[100001];
	scanf("%d",&n);
	while(n--)
    {
		int f=-1;
		int time=0;
		scanf("%s",a);
        scanf("%s",b);
        getNext(b);
		int i=0,j=0;
        int lenb = strlen(b);
        int lena = strlen(a);
		while(i<lena)
        {
            if(j==-1||a[i]==b[j])
            {
				i++;
                j++;
			}
            else
            {
				j=nexts[j];
			}
			if(j==lenb)
            {
				time++;
				if(f==-1)
					f=i-j;
				j=0;
				if(lenb>1) i--;
			}
		}
		printf("%d %d\n",f+1,time);
	}
	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

 

#include<stdio.h>
#include<string.h>
#define N 1000010
char p[N];
int n;
int next[N];
int main()
{
    scanf("%s",p+1);
    n=strlen(p+1);
    int j=0,i;
    for(i=2;i<=n;i++)  //对本串构造出next数组,这边注意不能把next[0]赋值为-1;                     
    {
        while(j&&p[i]!=p[j+1]) 
            j=next[j];
        if(p[i]==p[j+1]) 
            j++;
        next[i]=j;
    }
    int x=n-2*next[next[n]];  //不明白可以写一下,第二长的前缀
    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 
#include <stdio.h>
#include <string.h>
void DNA(char *str)
{
    int n,i,j;
    n=strlen(str);
    printf("%s ",str);
    for(i=1;i<n;i++)
    {
        str[n]=str[0];
        for(j=1;j<=n;j++)
        {
            str[j-1]=str[j];
        }
        str[j-1]='\0';
        printf("%s ",str);
    }
}
int main()
{
    int m,i;
    char a[510];
    scanf("%d",&m);
    for(i=0;i<m;i++)
    {
        scanf("%s",a);
        DNA(a);
        printf("\n");
    }
    return 0;
}

7-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 a[101][101],b[101][101],n,x,f=1,i,j;
	scanf("%d",&n);
	for(i=1;i<=n;i++)
    {
		for(j=1;j<=n;j++)
        {
			scanf("%d",&x);
			a[i][j]=x;
		} 
	}
	for(i=1;i<=n;i++)
    {
		for(int j=1;j<=n;j++)
        {
			if(a[i][j]!=a[j][i])
                f=0;
		} 
	}
	if(f) 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

wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw==
#include<stdio.h>
int main()
{
    int n,m,d;
    scanf("%d %d %d",&n,&m,&d);
    int i,j;
    int k[10],s[10],h[10];
    int q=0;
    int a[101][101]={0},b[101][101]={0};
    while(d--)
    {
        int p,f,c;
        scanf("%d %d %d",&p,&f,&c);
        for(i=0;i<n;i++)
        {
            for(j=0;j<m;j++)
            {
                if(f==j&&p==i)
                {
                    a[i][j]=c;
                }
            }
        }
        for(i=0;i<n;i++)
        {
            for(j=0;j<n;j++)
            {
                b[i][j]=a[j][i];
            }
        }
    }
    for(i=0;i<m;i++)
    {
        for(j=0;j<n;j++)
        {
            if(b[i][j]!=0)
            {
                k[q]=i;
                s[q]=j;
                h[q]=b[i][j];
                q++;
            }
        }
    }
    for(i=0;i<q;i++)
    {
         printf("%d %d %d\n",k[i],s[i],h[i]);
    }
    return 0;
}

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
#include<stdio.h>
int main()
{
    int m,n,t1,t2;
    int a[101][101],b[101][101];
    scanf("%d %d %d %d",&m,&n,&t1,&t2);
    int i,j;
    while(t1--)
    {
        int c,d,e;
        scanf("%d %d %d",&c,&d,&e);
        for(i=0;i<m;i++)
        {
            for(j=0;j<n;j++)
            {
                if(c==i&&d==j)
                {
                    a[i][j]=e;
                }
            }
        }
    }
    while(t2--)
    {
        int f,g,h;
        scanf("%d %d %d",&f,&g,&h);
        for(i=0;i<m;i++)
        {
            for(j=0;j<n;j++)
            {
                if(f==i&&g==j)
                {
                    b[i][j]=h;
                }
            }
        }
    }
    int sum[101][101];
    for(i=0;i<m;i++)
    {
        for(j=0;j<n;j++)
        {
            sum[i][j]=a[i][j]+b[i][j];
        }
    }
    int cot=0;
    for(i=0;i<m;i++)
    {
        for(j=0;j<n;j++)
        {
            if(sum[i][j]!=0)
            {
                cot++;
            }
        }
    }
    printf("%d %d %d\n",m,n,cot);
    for(i=0;i<m;i++)
    {
        for(j=0;j<n;j++)
        {
            if(sum[i][j]!=0)
            {
                printf("%d %d %d\n",i,j,sum[i][j]);
            }
        }
    }
    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
#include<stdio.h>
typedef struct {
    int p,i, j;
    int data;
}triple;
typedef struct {
    triple data[10];
    int n, m, num;
}TSMATRIX;

TSMATRIX ChangeMatr(TSMATRIX M, TSMATRIX T) {
    T.m = M.n;
    T.n = M.m;
    T.num = M.num;

			if (T.num) {
				int q = 0;
				int col;
				for (col = 0; col <= M.m; ++col) {
        			int p;
					for (p = 0; p < M.num; ++p) {
						if (M.data[p].j == col) {
							T.data[q].i = M.data[p].j;
							T.data[q].j = M.data[p].i;
							T.data[q].data = M.data[p].data;
							q++;
						}
					}
				}
			}
			return T;
}

int main() {
    TSMATRIX M;
   
    int k=0;
    scanf("%d %d %d",&M.m,&M.n,&M.num); 
    while(k!=M.num){
    	scanf("%d %d %d",&M.data[k].i,&M.data[k].j,&M.data[k].data);
    	k++;
    }
    
    TSMATRIX T;
    int k1;
    for (k1 = 0; k1 <=M.num; k1++) {
        T.data[k1].i = 0;
        T.data[k1].j = 0;
        T.data[k1].data = 0;
    }
    T = ChangeMatr(M, T);
    int i;
    for (i = 0; i < T.num; i++) {
     	T.data[i].p = i;
    }

     for (i = 0; i < T.num; i++) {
    	int j;
    	int k = M.data[i].data;
    	for(j = 0; j < T.num; j++){	
    		if(T.data[j].data == k){
    			 printf((i+1 == T.num) ? "%d %d %d %d":"%d %d %d %d\n", T.data[j].p, T.data[j].i, T.data[j].j, T.data[j].data);	
    		}
    	}
	}
    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
#include<stdio.h>
int dp[5050][5050];//一定要开得大一些
int m,n,ans=-999999,temp,num;
int main()
{
    int i,j,k;
    scanf("%d %d",&m,&n);
    for(i=1;i<=m;i++)
        for(j=1;j<=n;j++)
        {
            scanf("%d",&num);
            dp[i][j]=dp[i-1][j]+num;//记录每个[i,j]矩阵的总和
        }
    int x1,x2,y1,y2;
    for(i=1;i<=m;i++)
    {//一层循环,用于控制子矩阵的下边界
        for(j=1;j<=i;j++)
        {//二层循环,用于控制子矩阵的上边界
            temp=0;
            int yy=1;
            for(k=1;k<=n;k++)
            {//三层循环用于控制子矩阵的右边界
                temp+=(dp[i][k]-dp[j-1][k]);
                if(temp>ans)//如果值大于最大值则更新
                {
                    ans=temp;
                    x2=i;
                    y2=k;
                    x1=j;
                    y1=yy;
                }
                if(temp<0)
                {
                    temp=0;
                    yy=k+1;
                }
            }
        }
    }
    printf("%d\n",ans);
    printf("%d %d %d %d",x1,x2,y1,y2);
}

 

  • 1
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

CRAEN

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

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

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

打赏作者

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

抵扣说明:

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

余额充值