[每日习题]动态规划——公共子串计算 通配符匹配——牛客习题

        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道较难题(通配符匹配),包含递推公式的推导,本文旨在记录,如有需要,希望能有所帮助!!

猜你喜欢

转载自blog.csdn.net/bang___bang_/article/details/132042721