【Interleaving String】cpp

题目:

Given s1s2s3, find whether s3 is formed by the interleaving of s1 and s2.

For example,
Given:
s1 = "aabcc",
s2 = "dbbca",

When s3 = "aadbbcbcac", return true.
When s3 = "aadbbbaccc", return false.

代码:

“merge sort + stack”

复制代码
        struct LastMatch{
            int i1;
            int i2;
            int i3;
            LastMatch(int i1, int i2, int i3): i1(i1), i2(i2), i3(i3){}
        };
        static bool isInterleave(string s1, string s2, string s3)
        {
            const int n1 = s1.size();
            const int n2 = s2.size();
            const int n3 = s3.size();
            if ( n1+n2 != n3 ) return false;
            stack<LastMatch> sta;
            int i1=0,i2=0,i3=0;
            while ( i1<n1 || i2<n2 || i3<n3 )
            {
                if ( s1[i1]==s2[i2] && s2[i2]==s3[i3] ){
                    sta.push(LastMatch(i1,i2,i3));
                    i1++; i3++;
                }
                else if ( s1[i1]==s3[i3] ){ 
                    i1++; i3++;
                }
                else if ( s2[i2]==s3[i3] ){ 
                    i2++; i3++; 
                }
                else if ( !sta.empty() ){
                    LastMatch lm = sta.top(); sta.pop();
                    i1 = lm.i1; i2 = lm.i2; i3 = lm.i3;
                    i2++; i3++;
                }
                else{
                    return false;
                }
            }
            return i1==n1 && i2==n2 && i3==n3;
        }
复制代码

"dp"

复制代码
class Solution {
public:
        bool isInterleave(string s1, string s2, string s3)
        {
            const int n1 = s1.size();
            const int n2 = s2.size();
            const int n3 = s3.size();
            if ( n1+n2 != n3 ) return false;
            vector<vector<bool> > dp(n1+1, vector<bool>(n2+1, false));
            dp[0][0] = true;
            // check s1 boundary
            for ( int i = 1; i <= n1; ++i ){
                dp[i][0] = s1[i-1]==s3[i-1] && dp[i-1][0];
            }
            // check s2 boundary
            for ( int i = 1; i <= n2; ++i ){
                dp[0][i] = s2[i-1]==s3[i-1] && dp[0][i-1];
            }
            // dp process
            for ( int i = 1; i<=n1; ++i )
            {
                for ( int j = 1; j<=n2; ++j )
                {
                    dp[i][j] = ( s1[i-1]==s3[i+j-1] && dp[i-1][j] )
                    || ( s2[j-1]==s3[i+j-1] && dp[i][j-1] );
                }
            }
            return dp[n1][n2];
        }
};
复制代码

tips:

这道题第一版采用“merge sort + stack”,有一个大集合过不去,报超时(但即使跟可以AC的dp方法对比,“merge sort+stack”过这个大集合也仅仅慢了不到10%,在数量级上应该没有差别,时间复杂度都是O(n²))

dp的解法是学习网上的解法,理解如下:

dp[i][j]表示s1[0~i-1]与s2[0~j-1]是否匹配s3[0~i+j-1]

因此为了方便,定义dp[n+1][m+1],多一个维度,目的是保证从s1中取的个数从0到n都可以表示(s2同理)。

可以写出来dp的通项公式:

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

表示s3第i+j个元素要么由s1匹配上,要么由s2匹配上。

最后返回dp[n1][n2]就是所需的结果。

整个dp的过程并不复杂,思考下如何得来的:

1. dp取两个维度是因为s1和s2两个变量

2. 之前自己思考dp的时候,考虑的是每个位置可以由s1或者s2其中的元素表示,但是这样考虑起来就太复杂了;网上的思路并么有考虑到这么复杂,而是仅仅考虑s3中总共就这么长字符串,某个长度的字符串可以从s1和s2各取几个

============================================

上述的dp过程的空间复杂度是O(n²)的,再采用滚动数组方式,把空间复杂度降低到O(n),代码如下:

复制代码
class Solution {
public:
        bool isInterleave(string s1, string s2, string s3)
        {
            const int n1 = s1.size();
            const int n2 = s2.size();
            const int n3 = s3.size();
            if ( n1+n2 != n3 ) return false;
            vector<bool> dp(n2+1, false);
            // check s2 boundary
            dp[0] = true;
            for ( int i = 1; i<=n2; ++i )
            {
                dp[i] = s2[i-1]==s3[i-1] && dp[i-1];
            }
            // dp process
            for ( int i = 1; i<=n1; ++i )
            {
                dp[0] = s1[i-1]==s3[i-1] && dp[0];
                for ( int j = 1; j<=n2; ++j )
                {
                    dp[j] = ( s1[i-1]==s3[i+j-1] && dp[j] ) || ( s2[j-1]==s3[i+j-1] && dp[j-1] ); 
                }
            }
            return dp[n2];
        }
};
复制代码

tips:如果二维的dp过程只跟紧上一次的dp过程有关,就可以退化为滚动数组形式的一维dp过程。

=======================================

第二次过这道题,参照dp的思路写了一遍。有个细节就是dp递推公式的时候“s3[i+j-1]”不要写成s3[i-1]或者s3[j-1]。

复制代码
class Solution {
public:
    bool isInterleave(string s1, string s2, string s3) {
            if ( (s1.size()+s2.size())!=s3.size() ) return false;
            bool dp[s1.size()+1][s2.size()+1];
            fill_n(&dp[0][0], (s1.size()+1)*(s2.size()+1), false);
            dp[0][0] = true;
            for ( int i=1; i<=s1.size(); ++i )
            {
                dp[i][0] = dp[i-1][0] && s1[i-1]==s3[i-1];
            }
            for ( int i=1; i<=s2.size(); ++i )
            {
                dp[0][i] = dp[0][i-1] && s2[i-1]==s3[i-1];
            }
            for ( int i=1; i<=s1.size(); ++i )
            {
                for ( int j=1; j<=s2.size(); ++j )
                {
                    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] );
                }
            }
            return dp[s1.size()][s2.size()];
    }
};
复制代码

 

posted on   承续缘  阅读(229)  评论(0编辑  收藏  举报

编辑推荐:
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
阅读排行:
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 分享 3 个 .NET 开源的文件压缩处理库,助力快速实现文件压缩解压功能!
· Ollama——大语言模型本地部署的极速利器
· DeepSeek如何颠覆传统软件测试?测试工程师会被淘汰吗?

导航

< 2025年3月 >
23 24 25 26 27 28 1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31 1 2 3 4 5

统计

点击右上角即可分享
微信分享提示