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的長度

 

 

 

 

 

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