hello,大家好,这里是bang___bang_,本篇记录2道牛客习题,公共子串计算(中等),通配符匹配(较难),如有需要,希望能有所帮助!

目录
1️⃣公共子串计算
2️⃣通配符匹配
1️⃣公共子串计算
公共子串计算_牛客题霸_牛客网 (nowcoder.com)
描述
给定两个只包含小写字母的字符串,计算两个字符串的最大公共子串的长度。
注:子串的定义指一个字符串删掉其部分前缀和后缀(也可以不删)后形成的字符串。数据范围:字符串长度:1≤s≤150
进阶:时间复杂度:O(n^3) ,空间复杂度:O(n)
输入描述:
输入两个只包含小写字母的字符串
输出描述:
输出一个整数,代表最大公共子串的长度
示例1:
输入: asdfas
werasdfaswer
返回值:6
解题思路:
1.计算最大公共子串的长度,需要形成第i-1位置的子串长度提供给第i位置的子串。故采用动态规划。dp[ i ] [ j ]表示 s[ i ] 与 p[ i ] 构成子串的长度
2.子串长度是在前面求得的子串的长度下再+1。递推公式:dp[ i ] [ j ] = dp[ i-1 ] [ j-1 ] + 1

3.在两待匹配字符串前添加一个空串,方便我们从两个待匹配字符串首字符开始遍历。遍历从下标1开始,即从待匹配字符串的首字符,并且防止 i-1 和 j-1 越界,默认初始化值为0,相当于空串并不加入计算,只是为了方便我们去匹配。
4.使用局部变量maxlen,在每次匹配为子串时进行比较更新为最大长度。
代码实现:
#include <iostream>
#include<string>
#include<cmath>
#include<vector>
using namespace std;
int GetMaxLength(string s,string p)
{
    int maxlen=0;//记录最大公共字串长度
    s=" "+s;//添加空串
    p=" "+p;//添加空串
    int n=s.size();
    int m=p.size();
    vector<vector<int>>dp(n,vector<int>(m));//初始化为0,不影响计算长度
    //i=1,j=1;从待匹配字符串开始匹配(原字符串)
    for(int i=1;i<n;i++)
    {
        for(int j=1;j<m;j++)
        {
            if(s[i]==p[j])//匹配为子串
            {
                dp[i][j]=1+dp[i-1][j-1];    //获取长度
                maxlen=max(maxlen,dp[i][j]);//更新最大长度
            }
        }
    }
    return maxlen;
}
int main() {
    string str1,str2;
    while(cin>>str1>>str2)
    {
        cout<<GetMaxLength(str1,str2)<<endl;
    }    
    return 0;
}
 
2️⃣通配符匹配
通配符匹配_牛客题霸_牛客网 (nowcoder.com)
描述
请实现支持'?'and'*'.的通配符模式匹配
'?' 可以匹配任何单个字符。
'*' 可以匹配任何字符序列(包括空序列)。返回两个字符串是否匹配
函数声明为:
bool isMatch(string s,string p)
下面给出一些样例:isMatch("aa","a") → false
isMatch("aa","aa") → true
isMatch("aaa","aa") → false
isMatch("aa", "*") → true
isMatch("aa", "a*") → true
isMatch("ab", "?*") → true
isMatch("aab", "d*a*b") → false数据范围:字符串长度满足 0≤n≤1000
进阶:空间复杂度 O(1),时间复杂度 O(n)
示例1:
输入:"ab","?*"
返回值:true
示例2:
输入:"ab","*"
返回值:true
解题思路: s为待匹配字符串,p为含通配符字符串
1.通配符匹配,前一个位置匹配的结果要给后一个位置进行判断是否匹配,故采用动态规划。
dp[ i ] [ j ] 表示s[ i ] 和 p [ j ]匹配情况
2.根据规则可以将匹配情况划分为2种:
【1】p [ j ] = * ,*号可以匹配0至多个。
【2】p [ j ] != * ,也就是说是相同字符或者是?号,?号相当于万能符,必定和待匹配字符串匹配,效果相当于相同字符匹配。
3.推导递推公式:
【1】当p [ j ] = * ;去掉 * 号匹配的字符,看*前匹配的结果。j-1 去掉*号,i-num 去掉 * 号匹配的字符。
步骤一: 如果 * 号匹配0个,dp[ i ] [ j ] = dp[ i ] [ j-1 ]
如果 * 号匹配1个,dp[ i ] [ j ] = dp[ i-1 ] [ j-1 ]
如果 * 号匹配2个,dp[ i ] [ j ] = dp[ i-2 ] [ j-1 ]
如果 * 号匹配.....
步骤二:* 号可以匹配0至n个字符,也就是说上述情况都有可能发生,也就是采用并集。
即dp[ i ] [ j ] = dp[ i ] [ j-1 ] || dp[ i-1 ] [ j-1 ] || dp[ i-2 ] [ j-1 ] || ..........1️⃣
步骤三:将 i = i-1 1️⃣
得到 dp[ i-1 ] [ j ] = dp[ i-1 ] [ j-1 ] || dp[ i-2 ] [ j-1 ] || dp[ i-3 ] [ j-1 ] || .......... 2️⃣
步骤四:发现2️⃣与1️⃣后部分一致,进行替换。
得到最终递推公式:当p [ j ] == * ;dp[ i ] [ j ] = dp[ i ] [ j-1 ] || dp[ i-1 ] [ j ]
【2】当p [ j ] != *;dp[ i ] [ j ] = dp[ i-1 ] [ j-1 ] && (s[ i ] == p [ j ] || p[ j ] == '?' )前一个字符的匹配结果与当前匹配是否为相同字符或者通配符?共同决定当前位置的匹配结果。
4.添加空串,空串必定匹配设置为true;原s串待匹配串,不可能和添加的空串匹配,默认为false;如果原p串首字符为*有可能和添加的空串匹配,所以要从[0][1]开始匹配。
| * | ? | a | ||
| T | T | F | F | |
| a | F | |||
| b | F | |||
| a | F | 
代码实现:
class Solution {
  public:
    bool isMatch(string s, string p) {
        //添加空串
        s = " " + s;
        p = " " + p;
        int n = s.size();
        int m = p.size();
        vector<vector<bool>>dp(n, vector<bool>(m));//默认初始化为false
        dp[0][0] = true;//空串必定匹配设置true
        //原s串待匹配串,不可能和添加的空串匹配,i!=1,[i][0]默认为false
        for (int i = 0; i < n; i++) 
        {
            //如果原p串首字符为*有可能和添加的空串匹配,所以要从[0][1]开始匹配
            for (int j = 1; j < m; j++) 
            {
                if (p[j] != '*') {
                    //i&&j防止越界
                    dp[i][j] = i && j && dp[i - 1][j - 1] && (s[i] == p[j] || p[j] == '?');
                } else {
                    //i&&和j&&防止越界
                    dp[i][j] = (i && dp[i - 1][j]) || (j && dp[i][j - 1]);
                }
            }
        }
        return dp[n - 1][m - 1];
    }
}; 
文末结语,本篇记录了2道动态规划的牛客习题,1道中等题(公共子串计算);1道较难题(通配符匹配),包含递推公式的推导,本文旨在记录,如有需要,希望能有所帮助!!






![[Pytorch]卷积运算conv2d](https://img-blog.csdnimg.cn/5c7c1fefc62b46ac9fd9cd13ddf53621.png)












