Leetcode刷题笔记 97.交错字符串

97.交错字符串


时间:2020年7月18日
知识点:动态规划
题目链接: https://leetcode-cn.com/problems/interleaving-string/

题目
给定三个字符串 s1, s2, s3, 验证 s3 是否是由 s1 和 s2 交错组成的。

示例1
输入
s1 = “aabcc”, s2 = “dbbca”, s3 = “aadbbcbcac”
输出
true

示例2
输入
s1 = “aabcc”, s2 = “dbbca”, s3 = “aadbbbaccc”
输出
false

解法

  1. 一看就是个动态规划,但是动态转移不好弄
  2. dp[i][j] 代表s1的前i个字符和s2的前j个字符能否组成s3的前i+j个字符
  3. dp[i][j] = (dp[i-1][j]&&s1[i-1]==s3[i+j-1]) | (dp[i][j-1]&&s2[j-1]==s3[i+j-1])
dp数组
      0 1 2 3 4 5
     s2 d b b c a
0 s1  1 0 0 0 0 0
1 a   1 0 0 0 0 0
2 a   1 1 1 1 1 0
3 b   0 1 1 0 1 0
4 c   0 0 1 1 1 1
5 c   0 0 0 1 0 1

 下标 0 1 2 3 4 5 6 7 8 9
 s1: a a b c c
 s2: d b b c a
 s3: a a d b b c b c a c

第一个字符

  1. 可以和s1的第一个字符匹配
    dp[1][0] = dp[0][0]&&s1[1-1]==s3[1+0-1] = 1
  2. 可以和s2的第一个字符匹配
    dp[0][1] = dp[0][0]&&s2[1-1]==s3[1+0-1] = 0

两个字符可能的情况dp[2][0],dp[1][1],dp[0][2]

  1. dp[2][0] 代表 s3的2个字符都和s1匹配
    先判断s3的第1个字符是否和s1的第1个字符匹配,再判断s3的第2个字符(下标为1)是否和s1的第2个字符(下标为1)相等
  2. dp[1][1]代表 s3的2个字符各和s1的1个和s2的1个匹配
    1. 先判断dp[0][1],如果dp[0][1]=1说明s3的第1个字符是和s2的第1个字符匹配,再判断s1的第1个字符(下标为0)和s3的第1个字符(下标为0)是否相等
    2. 先判断dp[1][0],如果dp[1][0]=1说明s3的第1个字符是和s1的第1个字符匹配,再判断s2的第1个字符和s3的第1个字符是否相等
  3. dp[0][2]代表 s3的2个字符都和s2匹配
    先判断s3的第1个字符是否和s2的第1个字符匹配,再判断s3的第2个字符(下标为1)是否和s2的第2个字符(下标为1)相等

dp[3][2]也就是s3的前5个字符,是否能由s1的前3个字符和s2的前两个组成

  1. 先判断dp[2][2](s3的前4个字符是否能由s1的前2个字符s2的前两个组成),如果能组成判断s1的第3个字符(下标为2)是否和s3的第5个字符(下标为4)
    dp[3][2] = dp[2][2]&&s1[3-1]==s3[3+2-1]
  2. 先判断dp[3][1](s3的前4个字符是否能由s1的前3个字符s1的前两个组成),如果能组成判断s2的第2个字符(下标为1)是否和s3的第5个字符(下标为4)
    dp[3][2] = dp[3][2]&&s2[2-1]==s3[3+2-1]

总结:dp[i][j] = (dp[i-1][j]&&s1[i-1]==s3[i+j-1]) | (dp[i][j-1]&&s2[j-1]==s3[i+j-1])

代码

简单版本

#include <stdio.h>
#include <iostream>
#include <vector>
#include <cstring>
#include <math.h>
using namespace std;
class Solution {
public:
     bool isInterleave(string s1, string s2, string s3) {
         int m = s1.size();
         int n = s2.size();
         int r = s3.size();
         vector<vector<int> > dp(m+1,vector<int> (n+1,0));
         dp[0][0] = 1;
         //如果s1和s2加起来的长度都和s3的长度都不一样,false
         if(m+n!=r)
            return false;
         //循环遍历
         for (int i = 0; i <= m; i++) {
             for (int j = 0; j <=n; j++) {
                 int p = i + j - 1;//注意下标
                 if (i > 0) {//注意下标不能等于0,后面要减一
                    dp[i][j] |=(dp[i - 1][j] && s1[i - 1] == s3[p]);//注意下标
                 }
                 if (j > 0) {
                    dp[i][j] |= (dp[i][j - 1] && s2[j - 1] == s3[p]);
                 }
             }
         }
         return dp[m][n];
     }
 };
int main()
{
    string s1 = "aabcc";
    string s2 = "dbbca";
    string s3 = "aadbbcbcac";
    Solution s;
    cout<<s.isInterleave(s1, s2, s3);
}

优化空间复杂度,滚动数组

#include <stdio.h>
#include <iostream>
#include <vector>
#include <cstring>
#include <math.h>
using namespace std;
class Solution {
public:
    bool isInterleave(string s1, string s2, string s3) {
        int m = s1.size();
        int n = s2.size();
        int r = s3.size();
        vector<int> dp(n+1,0);
        dp[0]= 1;
        if(m+n!=r)
            return false;
        //dp只和上一次的数值有关,二维数组可压缩成一维
        for (int i = 0; i <= m; i++) {
            for (int j = 0; j <=n; j++) {
                int p = i + j - 1;
                if (i > 0) {
                    dp[j] &= s1[i - 1] == s3[p];
                }
                if (j > 0) {
                    dp[j] |= (dp[j - 1] && s2[j - 1] == s3[p]);
                }
            }
        }
        return dp[n];
    }
};
int main()
{
    string s1 = "aabcc";
    string s2 = "dbbca";
    string s3 = "aadbbcbcac";
    Solution s;
    cout<<s.isInterleave(s1, s2, s3);
}

今天也是爱zz的一天哦!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值