LeetCode 97: 交错字符串

 

这里我们考虑用 s1和 s2的某个前缀是否能形成 s3 的一个前缀。

这个方法的前提建立于:判断一个 s3的前缀(用下标 k表示),能否用 s1和 s2 的前缀(下标分别为 i和 j),仅仅依赖于 s1 前 i个字符和 s2 前 j个字符,而与后面的字符无关。

为了实现这个算法, 我们将使用一个 2D 的布尔数组 dp 。dp[i][j]表示用 s1的前 i和 s2的前 j个字符,总共 i+j个字符,是否交错构成 s3的前缀。为了求出 dp[i][j] ,我们需要考虑 两 种情况:

s1的第 i 个字符和 s2 的第 j 个字符都不能匹配 s3的第 k 个字符,其中 k=i + j 。这种情况下,s1和 s2的前缀无法交错形成 s3长度为 k 的前缀。因此,我们让 dp[i][j]为 False。

s1的第 i 个字符或者 s2的第 j 个字符可以匹配 s3的第 k个字符,其中 k=i+j 。假设匹配的字符是 x 且与 s1的第 i 个字符匹配,我们就需要把 x放在已经形成的交错字符串的最后一个位置。此时,为了我们必须确保 s1的前 (i-1)个字符和 s2的前 j 个字符能形成 s3的一个前缀。类似的,如果我们将 s2的第 j个字符与 s3的第 k 个字符匹配,我们需要确保 s1的前 i 个字符和 s2的前 (j-1) 个字符能形成 s3的一个前缀,我们就让 dp[i][j]为True 。

 

public class Solution {
    public bool IsInterleave(string s1, string s2, string s3)
    {
        if((s1.Length  + s2.Length) != s3.Length)
            return false;
        bool[,] dp = new bool[s1.Length + 1, s2.Length + 1];
        for(int i = 0; i <= s1.Length; i++)
        {
            for(int j = 0; j <= s2.Length; j++)
            {
                if(i == 0 && j == 0)
                    dp[i, j] = true;
                else if(i == 0)
                    dp[i, j] = dp[i, j - 1] && s2[j - 1] == s3[i+ j - 1];
                else if(j == 0)
                    dp[i, j] = dp[i - 1, j] && s1[i - 1] == s3[i+ j - 1];
                else
                    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.Length, s2.Length];
    }
}

复杂度分析

时间复杂度:O(m \cdot n)O(m⋅n) 。计算 dpdp 数组需要 m*nm∗n 的时间。

空间复杂度:O(m \cdot n)O(m⋅n)。2 维的 dpdp 数组需要 (m+1)*(n+1)(m+1)∗(n+1) 的空间。 mm 和 nn 分别是 s1s1 和 s2s2 字符串的长度。

优化:使用一维动态规划

这种方法与前一种方法基本一致,除了我们仅使用一维 dp数组去储存前缀结果。我们利用 dp[i-1]的结果和 dp[i]之前的结果来计算 dp[i],即滚动数组。

public bool IsInterleave(string s1, string s2, string s3)
    {
        if((s1.Length  + s2.Length) != s3.Length)
            return false;
        bool[] dp = new bool[s2.Length + 1];
        for(int i = 0; i <= s1.Length; i++)
        {
            for(int j = 0; j <= s2.Length; j++)
            {
                if(i==0 && j == 0)
                    dp[j] = true;
                else if(i == 0)
                    dp[j] = dp[j - 1] && s2[j - 1] == s3[i+ j - 1];
                else if(j == 0)
                    dp[j] = dp[j] && s1[i - 1] == s3[i+ j - 1];
                else
                    dp[j] = (dp[j] && s1[i - 1] == s3[i+ j - 1]) || dp[j - 1] && s2[j - 1] == s3[i+ j - 1];
            }
        }
        return dp[s2.Length];
    }

 

复杂度分析

时间复杂度:O(m⋅n);长度为 n 的 dp数组需要被填充 m 次。

空间复杂度:O(n);n是字符串 s1的长度

 

 

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章