第六周作业(等值字串,KMP匹配,大整数相乘,最长公共子串,判断两个字符串是否匹配,最长回文子串,年号字串)

目录

1.等值字串

2.KMP匹配

3.大整数相乘

4.最长公共子串

5.判断两个字符串是否匹配

6.最长回文字串

7.年号字串


补发一下,原来忘记发了。

1.等值字串

【问题描述】如果字符串的一个子串(其长度大于1)的各个字符均相同,则称之为等值子串。试设计一算法,求出串S中一个长度最大的等值子串;如果串S 中不存在等值子串,则输出信息no

【输入形式】输入一个字符串,并以!结束

【输出形式】输出第一个出现的最长字符串,如果没有输出no

【样例输入】aabc123abc123cc!

【样例输出】aa

【样例输入】abceebccadddddaaadd!

【样例输出】ddddd

#include<bits/stdc++.h>
using namespace std;
int main(){
	string c;
	cin >> c;
	int s = 0, num = 0, stemp = 0, a = 1;
	int len = c.length();
	for(int i = 1; i < len; i++){
		if(c[i] == c[i - 1]) a++;
		else {
			if(a > num) {
				num = a;
				s = stemp;
			}
			stemp = i;
			a = 1;
		}
	}
	if(num > 1)
		for(int i = s; i < s + num; i++){
			cout << c[i];
		}
	else cout << "no";
}

2.KMP匹配

【问题描述】KMP算法是字符串模式匹配算法中较为高效的算法之一,其在某次子串匹配母串失败时并未回溯母串的指针而是将子串的指针移动到相应的位置。

【输入形式】3组字符串,每组字符串占一行。每行包含由空格分隔的两个字符串,字符串仅由英文小写字母组成且长度不大于100。

【输出形式】每组数据输出1行,输出后一个字符串在前一个字符串中的位置,如果不匹配,则输出0。

【样例输入】

string str
thisisalongstring isa
nosubstring subt

【样例输出】

1

5

0

【提示】表示字符串的数据结构可以是字符数组或用串类实现。KMP算法调用很简单,但难的是理解算法的思想。掌握算法的思想才能说是掌握算法。

#include<bits/stdc++.h>
#define M 2000
using namespace std;
/*typedef struct
{
    char ch[ M ];
    int len;

}SString;*/
//int next[ M ] ;
int KMP( string T , string P, int next[] ,int len1 , int len2 )
{
    int i = 0 , j = 0;
    while( i < len1 && j < len2 )
    {
        if( j == -1)
        {
            i++;
            j=0;
        }
        else if( P[j] == T[i] )
        {
            i++;
            j++;
        }
              else j = next[ j ];
    }
    if( j < len2 )
        return -1;
    else return i-j;
}
/*void getNext( string P , int next[] ,int len2 )
{
    next[ 0 ] = -1;
    int j = 0, k = -1;
    while( j < len2 -1 )
        {
            if( k == -1)
            {
                next[ j + 1 ] = 0;
                j++;
                k=0;
            }
            else if( P[ k ] == P[ j ] )
            {
                next[ j + 1 ] = k + 1;
                j++;
                k++;
            }
            else
            {
                    k = next[ k ];
            }
        }
}*/
int main()
{
    int m=0;
    int next[ M ] ;
    string T ;
    string P ;


    while( cin >> T >> P )
        {   int len1 = T.size();
            int len2 = P.size();
            //getNext(  P, next ,len2 );
              next[ 0 ] = -1;
    int j = 0, k = -1;
    while( j < len2 -1 )
        {
            if( k == -1)
            {
                next[ j + 1 ] = 0;
                j++;
                k=0;
            }
            else if( P[ k ] == P[ j ] )
            {
                next[ j + 1 ] = k + 1;
                j++;
                k++;
            }
            else
            {
                    k = next[ k ];
            }
        }
            m=KMP(  T ,  P, next ,len1 , len2 );
            if(m != -1)
            cout << m+1  << endl;
            else
                cout<< "0" <<endl;
        }



}

3.大整数相乘

【问题描述】输出两个不超过100位的大整数的乘积。

要求用串这一章的“块链串”知识实现两个大整数的相乘。比如每一个结点存储5位,12345678983426801则需要4个结点;先实现大整数乘上一个一位数;再实现两个大数相加。

用这样的链式存储形式便于计算:12--->34567--->89834--->26801

或者:26801--->89834--->34567--->12

【输入形式】

两个大数

【输出形式】

相乘的结果

【样例输入】

1234567891011121314151617181920

2019181716151413121110987654321

【样例输出】

2492816912877266687794240983772975935013386905490061131076320

#include <bits/stdc++.h>
using namespace std;
int arr[210];//接收结果的一个数组
typedef struct Link//块链串
{
    int  Maxsize ;
    int  num[5];
    struct  Link*next;

}Link;
Link * Init ( Link *p , char s[] )//初始化块链串
{
    Link *head = p;
    for(int i = 0 ; s[i] != '\0' ; i++)
    {
        if(i != 0 && i%5 == 0)
        {
            p -> next = new  Link;
            p = p -> next;
        }
        p -> num [i % 5] = s[i] -'0';
        p -> Maxsize = i % 5 ;
    }
    p -> next = NULL;
    return head;
}
void multiplication(Link *head1 , Link *head2 )//大整数乘法
{
    Link *p,*q;
    int N = 0, M = 0 , i , j , Max = 0,m;
    //N,M记录偏移值
    //M处理第一个串的不同节点之间的相加时的定位
    //N处理另一个串
    //Max是当前最大长度


    for( p = head1 ; p != NULL ; p = p -> next )//遍历a
    {

        if(p != head1)

            N+=5;

        for( i = 0; i <= p -> Maxsize ; i++ )//实现两个大整数的每一位相乘
        {
            for( q = head2 ; q != NULL ; q = q -> next )
            {
                if( q != head2 )
                    M+=5;
                for( j = 0 ; j <= q -> Maxsize ; j++)
                {
                    m = M + N + i + j + 1;
                    arr[ m ] += q -> num [ j ] * p -> num[ i ];
                    //cout<<i<<" "<<j<<" "<<m<<endl;
                    Max = Max>m? Max :m;
                }
            }

            M=0;
        }
    }
    for( int k = Max ; k > 0 ; k-- )//进位问题
    {
        if( arr [ k ] >= 10 )
        {
            arr [ k - 1 ] += arr[ k ]/10;
            arr[ k ] %= 10;
        }
    }


    int k=0;
    if(arr [ k ] == 0)
        k++;
    for(; k <= Max ;  k++)
        cout<<arr [ k ];
        cout<<endl;


}
int main()
{
    char a[100] , b[100];
    cin >> a >> b ;
    Link*head1,*head2;
    head1 = new Link;
    head2 = new Link;
    head1 = Init ( head1 , a );
    head2 = Init ( head2 , b );
    multiplication( head1 , head2 );


}

4.最长公共子串

【问题描述】

给定两个字符串,求出它们两个最长的相同子字符串的长度。

最长公共子串(Longest Common Substring)是一个非常经典的面试题目,在实际的程序中也有很高的实用价值。同学们不应该单单只是写出该问题的基本解决代码而已,关键还是享受把算法一步步的优化,让时间和空间复杂度一步步的减少的惊喜。

【输入形式】

两个字符串

【输出形式】

最长的公共子串,若没有则输出“no”

【样例输入】

acbcbcef

abcbced

【样例输出】

bcbce

【温馨提示】

问题的关键不在于提交代码并通过测试数据,而是你是否真正掌握了所有求解的算法。

 这是一道dp题

#include <iostream>
using namespace std;
/*typedef struct stu
{
    int num;
    string s;
}stu;*/
//stu dp[50][50];
int main()
{   int dp;
    string  a , b ,temp , arr
    s;
    int  x , y ;
    cin >> a >> b ;
    int len1 = a.size();
    int len2 = b.size();
    x = len1 - 1;

    /*for( int i = 1; i <= len1 ; i++)
        for( int j = 1; j <= len2 ; j++)
        {
            if( a[ i - 1 ] == b[ j - 1 ] )
            {
            dp[ i ][ j ].num = dp[ i - 1 ][ j - 1].num + 1;
            dp[ i ][ j ].s = dp[ i - 1 ][ j - 1 ].s + b[ j - 1 ];
            }
            if( dp[ x ][ y ].num < dp [ i ][ j ].num)
            {
                x=i;
                y=j;
            }
        }
        if(dp[ x ][ y ].num)
            cout<< dp[ x ][ y ].s ;
        else
            cout<<"no";*/
    while(y != len2 )
    {
        dp = 0 ;
        temp = "";
        for(int i = x, j = y;i <len1 && j < len2 ; i++,j++)
        {
            if( a[ i ] == b[ j ] )
                dp++,temp +=  a[ i ];
            else
               {
                dp = 0 ; temp = "";
               }
            if( temp.size() > arr.size())
                arr = temp;
        }
      if(x) x--;
      else y++;

    }
      if( arr.size()) cout<< arr ;
        else cout<<"no";

    return 0;
}

5.判断两个字符串是否匹配

【问题描述】判断两个字符串是否匹配,其中一个字符串中包括通配符*或?(串)。*代表0个或多个字符,?代表一个字符
【输入形式】分两行入两个字符串,以#结束,其中一个字符串中包括通配符*或?(串),另一个为不包含*和?的确定字符串
【输出形式】判断两个字符串是否匹配,若匹配,输出yes,不匹配输出no
【样例输入】

 da?a*tu*e#
 datastructure#
【样例输出】
 yes
【样例说明】 第一个字符串中包含通配符,第二个字符串为确定字符串。字符串中可能有空格,字母均为小写字母。
【评分标准】 请尽量使用效率高的算法,如结合KMP算法的思想。 

提示:?可看做对任一字符的匹配,*可看做对给出的有效字符(串)的匹配

这是一道dp题 

#include<bits/stdc++.h>
using namespace std;
int main(){
	string a,b;
	getline(cin,a);
	getline(cin,b);
	int m = b.length();
    int n = a.length();
    vector<vector<bool> > dp(m + 1, vector<bool>(n + 1, false));
    dp[0][0] = 1;
    for(int i = 1; i <= n; ++i) {
        if(a[i - 1] == '*') dp[0][i] = 1;
        else break;
    }
    for(int i = 1; i <= m; ++i) {
        for(int j = 1; j <= n; ++j) {
            if(b[i - 1] == a[j - 1] || a[j - 1] == '?') {
                dp[i][j] = dp[i - 1][j - 1];
            }else if(a[j - 1] == '*' && (dp[i - 1][j] || dp[i][j - 1])) {
                dp[i][j] = 1;
            }else{
                dp[i][j] = 0;
            }
        }
    }
    if(dp[m][n]) cout << "yes" << endl;
    else cout << "no" << endl;
}

6.最长回文字串

【问题描述】给定一个字符串s,找出s里第一次出现的最长的回文子串。

【样例输入1】babad
【样例输出1】bab

【样例输入2】cbbd
【样例输出2】bb

 可以学一下“马拉车”算法

#include <bits/stdc++.h>
#define M 100
int main()
{
	char s[M];     //先设定一个字符串数组保存输入的字符串
	char t[M];     //再设定一个字符串数组保存回文字符串
	scanf("%s",s);
	int i,j,k,l;
	int j1;             //j1用来保存j的值(因为在后续的程序中j需要变化,但又不能破坏j的值)
	l=strlen(s);
	for(j=0;j<l-1;j++)
	{
		j1=j;           //j1算是j的替身
		for(k=l-1;k>0;k--)
		{
			if(s[j1]!=s[k])   //判断s[j1]同s[k]
			{
			    j1=j;
				memset(t,0,sizeof(t));
				continue;
			}
			else
			{
			    t[0]=s[j];
			    t[k-j]=s[k];
			    j1++;
			}
		}
		if(strlen(t)) break;
	}
	if(l==1||l==2&&t[0]=='\0')
	{
		t[0]=s[0];
	}
	for(i=0;i<l&&t[i]!='\0';i++)
	{
		printf("%c",t[i]);
	}
}

7.年号字串

【问题描述】这是一道蓝桥杯的真题。小明用字母 A 对应数字 1,B 对应 2,以此类推,用 Z 对应 26。对于 27 以上的数字,小明用两位或更长位的字符串来对应,例如 AA 对应 27,AB 对 应 28,AZ 对应 52,LQ 对应 329。
  请问 2019 对应的字符串是什么?请你编程解决该问题。

【输入形式】数字
【输出形式】字母
【样例输入】2019
【样例输出】BYQ

#include<bits/stdc++.h>
using namespace std;

int main(){
	int n,k=0,m=26;
	cin>>n;
	while(n>m){

			n-=m;
			k++;
			m*=26;

	}
	for(int i=0;i<=k;i++)
    {   m/=26;
        for(int j=0;j<26;j++)
        {
            if(n<=m){
		cout<<char(65+j);
           break;
            }
            else n-=m;
        }
	}
	return 0;
}

  • 1
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
最长回文子串是指在一个字符串最长的回文子序列。回文是指正着读和倒着读都一样的字符串。动态规划是解决最长回文子串问题的一种常用方法。动态规划的思想是将问题分解成子问题,通过求解子问题的最优解来得到原问题的最优解。在最长回文子串问题,我们可以使用一个二维数组dp[i][j]来表示从i到j的子是否为回文子。如果dp[i][j]为true,则表示从i到j的子是回文子,否则不是。我们可以通过以下步骤来求解最长回文子串: 1. 初始化dp数组,将所有dp[i][i]都设置为true,表示单个字符是回文子。 2. 遍历字符串s,从长度为2的子开始,依次判断每个子是否为回文子。如果是,则将dp[i][j]设置为true。 3. 在遍历的过程,记录最长回文子串的长度和起始位置。 4. 最后,通过起始位置和长度来截取最长回文子串。 下面是一个示例代码,可以帮助你更好地理解动态规划求解最长回文子串的过程: class Solution { public: string longestPalindrome(string s) { int len=s.size(); if(len<2) return s; bool dp[len][len];//布尔型,dp[i][j]表示从i到j是否构成回文 int max_count=1;//最大字串的长度 int start=0;//最长字串的起始位置 for(int j=0;j<len;j++) { for(int i=0;i<j;i++) { if(s[i]!=s[j]) dp[i][j]=false; else if((j-i)<3)//(j-1)-(i+1)+1<2表示dp[i][j]的最大字串长度为1 dp[i][j]=true; else { dp[i][j]=dp[i+1][j-1]; } if((j-i+1)>max_count&&dp[i][j]) { max_count=j-i+1; start=i; } } } return s.substr(start,max_count);//截取字符串 } };

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值