刷题之动态规划-两个数组

本文介绍了动态规划在处理字符串问题中的五个实例,包括最长公共子序列、最长重复子数组、不相交的线、不同子序列计数以及通配符和正则表达式匹配,展示了如何使用dp数组进行状态转移和初始化。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

前言

大家好,我是jiantaoyab,开始刷动态规划的两个数组类型相关的题目

动态规划5个步骤

  1. 状态表示 :dp数组中每一个下标对应值的含义是什么>dp[i]表示什么
  2. 状态转移方程: dp[i] 等于什么
  3. 1 和 2 是动态规划的核心步骤,第三步是初始化,保证填表的时候不越界
  4. 填表顺序:为了保证填写当前状态的时候,所需要的状态已经计算过
  5. 返回值

最长公共子序列

image-20240410090952909

题目分析

image-20240410095204308

代码

class Solution {
public:
    int longestCommonSubsequence(string text1, string text2) {
      int m = text1.size(), n = text2.size();
      //增加一行和一列 dp[i - 1][j - 1]的时候不会越界
      vector<vector<int>> dp(m + 1, vector<int>(n + 1));

      //初始化
      text1 = " " + text1, text2 = " " + text2;
      for(int i = 1; i <= m; i++)
      {
        for(int j = 1; j <= n; j++)
        { 
          if(text1[i] == text2[j]) dp[i][j] = dp[i - 1][j - 1] + 1;
          else
          dp[i][j] = max(dp[i][j - 1], dp[i - 1][j]);
        }
      }

      return dp[m][n];
    }
}; 

最长重复子数组

image-20240413085655636

代码

class Solution {
public:
    int findLength(vector<int>& nums1, vector<int>& nums2) {
      int m = nums1.size(), n = nums2.size();
      vector<vector<int>> dp (m + 1, vector<int>(n + 1));
      int ret = 0;
        for(int i = 1; i <= m; i++)
        {
          for(int j = 1; j <= n; j++)
          {
            if(nums1[i - 1] == nums2[j - 1]) dp[i][j] = dp[i - 1][j - 1] + 1 , ret = max(dp[i][j], ret);
            else
            {
              dp[i][j] = 0;
            }
          }
        }
        return ret;
    }
};

不相交的线

image-20240410100519921

代码

这道题目和上一道题目很像,不过是在数组中最长公共的子序列

class Solution {
public:
    int maxUncrossedLines(vector<int>& nums1, vector<int>& nums2) {
        int m = nums1.size(), n = nums2.size();
        //避免dp[i - 1][j - 1]越界
        vector<vector<int>> dp (m + 1, vector<int>(n + 1));
        for(int i = 1; i <= m; i++)
        {
          for(int j = 1; j <= n; j++)
          {
            if(nums1[i - 1] == nums2[j - 1]) dp[i][j] = dp[i - 1][j - 1] + 1;
            else
            {
              dp[i][j] = max(dp[i - 1][j], dp[i][j - 1]);
            }
          }
        }
        return dp[m][n];
    }
};

不同的子序列

image-20240411095151339

题目分析

image-20240411102621891

代码

class Solution {
public:
    int numDistinct(string s, string t) {
        int m = t.size(), n = s.size();

        vector<vector<int>> dp(m + 1, vector<int>(n + 1));

        for(int j = 0; j <= n; j++) dp[0][j] = 1; //初始化

        for(int i = 1; i <= m; i++)
        {
          for(int j = 1; j <= n; j++)
          {
            dp[i][j] += dp[i][j - 1];
            if(t[i - 1] == s[j - 1]) dp[i][j] += dp[i - 1][j - 1] % 10000000007; 
                            
          }
        }
        return dp[m][n];
    }
};

通配符匹配

image-20240411105113954

题目分析

image-20240411114621577

初始化

image-20240412083947801

代码

class Solution {
public:
    bool isMatch(string s, string p) {
      int m = s.size(), n = p.size();
      vector<vector<bool>> dp(m + 1, vector<bool>(n + 1));
      s= " " + s, p = " " + p;
      //初始化
      dp[0][0] = true; //空串匹配空串
      for(int j = 1; j <= n; j++) 
      {
        if(p[j] == '*') dp[0][j] = true;
        else break;
      }
      for(int i = 1; i <= m; i++)
      {
        for(int j = 1; j <= n; j++)
        {
          if(p[j] == s[i] && dp[i -1][j - 1] == true) dp[i][j] = true;
          else if(p[j] == '?' &&  dp[i - 1][j- 1] == true) dp[i][j] = true;
          else if(p[j] == '*') dp[i][j] = dp[i - 1][j] || dp[i][j - 1];
       
        }
      }
      return dp[m][n];

    }
};

正则表达式匹配

image-20240412080453240

题目分析

这里的*是根据前面的字符来匹配的,不能单独使用。

image-20240412093228543

image-20240412093240354

代码

class Solution {
public:
    bool isMatch(string s, string p) {
      int m = s.size(), n = p.size();
      vector<vector<bool>> dp(m + 1, vector<bool>(n + 1));
      //初始化
      dp[0][0] = true;
      s = ' ' + s , p = ' ' + p;
      for(int j = 2; j <= n; j += 2)
      {
        if(p[j] == '*') dp[0][j] = true;
        else break;
      }

      for(int i = 1; i <= m; i++)
      {
        for(int j = 1; j <= n; j++)
        {
          if( p[j] == '*')
           dp[i][j] = dp[i][j - 2] || (p[j - 1] == '.' || p[j - 1] == s[i]) && dp[i -1][j];    
          else         
           dp[i][j] = (s[i] == p[j] || p[j] == '.') && dp[i - 1][j - 1] ;

     
        }
      }
      return dp[m][n];
    }
};

交错字符串

image-20240411134821878

题目分析

image-20240411141632827

代码

class Solution {
public:
    bool isInterleave(string s1, string s2, string s3) {
      int m = s1.size(), n = s2.size();
      if(n + m != s3.size()) return false;
       vector<vector<bool>> dp(m + 1, vector<bool>(n + 1));
      s1 = " " + s1, s2 = " " + s2, s3 = " " + s3;
      //初始化
      dp[0][0] = true;
      for(int i = 1; i <= n; i++) 
        if(s2[i] == s3[i]) dp[0][i] = true;
        else break;
      for(int j = 1; j <= m; j++) 
        if(s1[j] == s3[j]) dp[j][0] = true;
        else break;
      
      for(int i = 1; i <= m; i++)
      {
        for(int j = 1; j <= n; j++)
        {
          if(s1[i] == s3[i + j] && dp[i - 1][j]) dp[i][j] = true;
          else if(s2[j] == s3[i + j] && dp[i][j - 1]) dp[i][j] = true;
        }
      }
      return dp[m][n];
    }
};

两个字符串的最小ASCII删除和

image-20240412093337675

代码

class Solution {
public:
    int minimumDeleteSum(string s1, string s2) {
      int m = s1.size(), n = s2.size();
      //dp[i][j] 表示s1[0, i]和s2[0, j]公共子串ascii值最大
      vector<vector<int>> dp (m + 1, vector<int>(n + 1));
      
      for(int i = 1; i <= m; i++)
      {
        for(int j = 1; j <= n; j++)
        {
          dp[i][j]  = max(dp[i][j - 1], dp[i - 1][j]);
          if(s1[i - 1] == s2[j - 1]) 
          dp[i][j] = max(dp[i][j], dp[i - 1][j - 1] + s1[i - 1]);       
        }
      } 
      int sum = 0;
      for(auto c : s1) sum += c;
      for(auto c : s2) sum += c;
      return sum - dp[m][n] - dp[m][n];
    }
};

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值