牛客竞赛每日俩题 - Day3

14天阅读挑战赛

目录

动态规划思想

经典DP

简单的数学问题


动态规划思想

查找两个字符串a,b中的最长公共子串_牛客题霸_牛客网

 

思路:

        本题需要用动态规划求解,MCS[i][j] 记录短字符串 s1 i 个字符和长字符串 s2 j 个字符的最长子串的长度,初始化所有值为 0 。当 s1[i-1] = s2[j-1] 时, MCS[i][j] = MCS[i - 1][j - 1] + 1 ,这里使用一个额外的值 start 来记录最长子串在短字符串 s1 中出现的起始位置, maxlen 记录当前最长子串的长度,当 MCS[i][j] > maxlen 时, maxlen = MCS[i][j] , 则 start = i - maxlen ;档 s1[i-1] != s2[j-1] 时不需要任何操作,最后获取 substr(start, maxlen) 即为所求

1、转移方程为:   如果遍历到的该位两个字符相等,则此时长度等于两个前一位长度+1,

(dp[i][j]=dp[i−1][j−1]+1),如果遍历到该位时两个字符不相等,则置为0,因为这是子串,必须连续相等,断开要重新开始。 

2、

vector<vector<int>> MSC(len1+1,vector<int>(len2+1,0));

解析:

用vector构造二维数组,用len2+1构造行并全部初始化为0,用vector<int>(len2+1,0)(初始化为0的行)构造len1+1个列;即:将整个数组初始化为0

 (建议先看第二题)

#include <iostream>
#include<vector>
using namespace std;

string getcomsubstr(string &s1,string &s2)
{
    if(s1.size()>s2.size())
        swap(s1,s2);//要输出在较短串中最先出现的
    int len1=s1.size();
    int len2=s2.size();
    vector<vector<int>> MSC(len1+1,vector<int>(len2+1,0));
    int start=0,maxsize=0;

    for(int i=1;i<=len1;i++)    //一较短串为基础,才能找较短串中最先出现的
        for(int j=1;j<=len2;j++)
        {
            if(s2[j-1]==s1[i-1]) 
                MSC[i][j]=MSC[i-1][j-1]+1;
            
            if(MSC[i][j]>maxsize)//有更长公共子串,更新长度
            {
                maxsize=MSC[i][j];
                //以i结尾的最大长度max,则起始位置为i-max
                start=i-maxsize;
            }
        }
        return s1.substr(start,maxsize);
}

int main() 
{
    string str1,str2;
    while(cin>>str1>>str2)
    {
        string sub=getcomsubstr(str1,str2);
        cout<<sub<<endl;
    }
    return 0;
}

经典DP

公共子串计算_牛客题霸_牛客网

 

思路:

        求最大公共子串,使用递推实现 假设 x(i): 字符串第 i 个字符 y(j): 字符串第 j 个字符 dp[i][j]: x(i),y(j) 结尾的最大子串长度 比如: x: "abcde" y:"bcdae" dp[2][1]: x(2),y(1) 结尾的最大子串长度 即: x 遍历到 "abc", y 遍历 "bc", 都以字符 'c' 结尾时最大公共子串为 "bc" 故:当计算 dp[i][j] 时,首先看 x(i),y(j) 的值:
1 : x(i) == y(j) 当前两个字符串结尾的字符相等, dp[i][j] = dp[i-1][j-1] + 1 即个它的长度加 1 (2 : x(i) != y(j) 当前两个字符 串结尾的字符不相等,说明没有以这连个字符结尾的公共子串 即 dp[i][j] = 0
(3 : dp[0][j] dp[i][0] 表示以 某个子串的第一个字符结尾,最大长度为 1 如果 x(0) == y(j) 或者 x(i) == y(0), 则长度为 1 ,否则为 0 dp 中的 所有元素计算完之后,从中找打最大的值输出

 

#include <iostream>
#include<vector>
using namespace std;

int getcomsubstr(string &s1,string &s2)
{

    int len1=s1.size();
    int len2=s2.size();
    vector<vector<int>> MSC(len1+1,vector<int>(len2+1,0));
    int start=0,maxsize=0;

    for(int i=1;i<=len1;i++)   
        for(int j=1;j<=len2;j++)
        {
            if(s2[j-1]==s1[i-1]) 
                MSC[i][j]=MSC[i-1][j-1]+1;
            
            if(MSC[i][j]>maxsize)//有更长公共子串,更新长度
            {
                maxsize=MSC[i][j];
            }
        }
        return maxsize;
}

int main() 
{
    string str1,str2;
    while(cin>>str1>>str2)
    {
        int maxv=getcomsubstr(str1,str2);
        cout<<maxv<<endl;
    }
    return 0;
}

简单的数学问题

洗牌_牛客题霸_牛客网

看到题目字数和样例人麻了?其实只是一道小学奥数题

 思路:

每次读取一个数之后,算出他经过 k 次洗牌后的位置,只用一个长度为 2n 数组用来输出
根据当前数的位置,可以算出经过一次洗牌后的位置
  1. 如果当前数小于等于n(即在左手),则他下次出现的位置是 2*当前位置
  2. 与之对应的当前位置 + n(即在右手)的牌,则他下次出现的位置是 2*当前位置 + 1

 

高效率地把一个数组的内容复制给另一个数组:

#include <stdio.h>
#define SIZE 3
int main()
{
	int a[SIZE], b[SIZE]={1,2,3};
	register int *x, *y;
	for( x = a, y = b ; y < &b[SIZE] ; )
		*x++ = *y++;
	return 0;
}

 

#include <iostream>
using namespace std;

int main() {
    int T,n,k;
    cin>>T;
    while(T--)
    {
        cin>>n>>k;
        int num=2*n;
        int card[num+1];
        for(int i=0;i<num;i++) cin>>card[i];

        while(k--)
        {
            int tmp[num+1];
            int *x,*y;
            for(x=tmp,y=card;y<&card[num+1];) *x++=*y++;
                
            for(int j=0;j<n;j++)
            {
                card[2*j]=tmp[j];    //左手的牌排放的位置
                card[2*j+1]=tmp[j+n];//右手的牌排放的位置
            }
        }
        for(int i=0;i<num-1;i++) cout<<card[i]<<" ";
        cout<<card[num-1]<<endl;
    }
}
// 64 位输出请用 printf("%lld")

 

 

 

  • 6
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

小黄同学LL

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

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

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

打赏作者

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

抵扣说明:

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

余额充值