LeetCode:97. 交錯字符串

1. 題目描述

給定三個字符串 s1s2s3, 驗證 s3 是否是由 s1 和 s2 交錯組成的。

示例 1:

示例 2:

2. 解題思路

  s1 , s2 組成 s3 過程中不能改變 s1, s2 的字符順序,示例2中 s1, s2 字符和與 s3 相同,但由於不能改變s1, s2 的字符順序,結果爲 false.

90%的字符串問題可由動態規劃解決,本題就是一道動態規劃問題。

首先找出狀態轉移方程:

假設 dp[i][j] 代表 s1 的前 j 個字符與 s2 的前 i 個字符能否交錯組成 s3 的 前 (i + j) 個字符。

如果爲True,又代表着 s1 的第 j 個字符或者 s2 的第 i 個字符與 s3 的第(i + j)個字符相等。

接下來找出狀態轉移方程:

     dp[i][j] = 1, s1.charAt(j-1) == s3.charAt(i+j-1) && dp[i][j-1] == 1;

     dp[i][j] = 1, s2.charAt(i-1) == s3.charAt(i+j-1) && dp[i-1][j] == 1;

     其餘情況都爲0;

    即當 s1 的第 j 個字符或者 s2 的第 i 個字符與 s3 的第(i + j)個字符相等,並且 dp[i][j-1] 或者 dp[i-1][j] 等於 1.

   dp[i][j-1] 或者 dp[i-1][j]等於 1 代表着能交錯組成s3 的 前 (i + j-1) 個字符。如果s1 的第 j 個字符與 s3 的第(i + j)個字符

   相等,只需能交錯組成s3 的 前 (i + j-1) 個字符,由於 s1 的第 j 個字符用於組成s3 的第(i + j)個字符,所以需要dp[i][j-1] 爲 1. 

   同理s2 的第 i 個字符與 s3 的第(i + j)個字符相等需要dp[i-1][j] 爲 1.

   爲方便理解以示例1數據填表:

   s3 爲 a a d b b c b c a c

   先填邊界,即單一字符串匹配情況

座標   0 1 2 3 4 5
    s1 a a b c c
0 s2   1 1 0 0 0
1 d 0          
2 b 0          
3 b 0          
4 c 0          
5 a 0          

 接下來先從s3的前1個字符開始,需填(0,1),(1,0),由上圖可知在邊界賦值時已完成,接下來考慮s3的前兩個字符,需填座標(2,0)(0,2)(1,1)。(2,0),(0,2)已完成,填座標(1,1):判斷 s1 第1個或者 s2 第1個是否與 s3 第2個相等。s3 第二個爲a,所以s1 第1個與之相等。接下  來還需判斷是否能組成 s3 的第 1 個字符,與(1,1)相鄰座標相加爲1的有(1,0),(0,1),由於s1第1個被用來與 s3 第2個匹配,所以只能判斷(1,0),由於dp[1][0]爲0,所以不滿足條件,dp[1][1]爲0:

座標   0 1 2 3 4 5
    s1 a a b c c
0 s2   1 1 0 0 0
1 d 0 0        
2 b 0          
3 b 0          
4 c 0          
5 a 0          

 按照轉移方程填表,從s3的子串開始:

 s3前1個字符,填(1,0)(0,1)

 s3前2個字符,填 (2,0)(0,2)(1,1)

 s3前3個字符,填 (3,0)(0,3)(2,1)(1,2)

 s3前4個字符,填 (4,0)(0,4)(1,3)(3,1)(2,2)

 s3前5個字符,填 (5,0)(0,5)(2,3)(3,2)(1,4)(4,1)

 s3前6個字符,填 (5,1)(1,5)(3,3)(2,4)(4,2)

 s3前7個字符,填 (2,5)(5,2)(3,4)(4,3)

 s3前8個字符,填 (3,5)(5,3)(4,4)

 s3前9個字符,填 (4,5)(5,4)

 s3前10個字符,填 (5,5)

 由於s1,s2長度限制,有些組合情況沒有,如(6,0),(1,7)等,編程時需注意。 

最終可得:

座標   0 1 2 3 4 5
    s1 a a b c c
0 s2   1 1 0 0 0
1 d 0 0 1 1 0 0
2 b 0 0 1 1 1 0
3 b 0 0 1 0 1 1
4 c 0 0 1 1 1 0
5 a 0 0 0 0 1 1

3. 示例代碼

class Solution {
    public boolean isInterleave(String s1, String s2, String s3) {
        int length = s3.length();
        // 特殊情況處理
        if(s1.isEmpty() && s2.isEmpty() && s3.isEmpty()) return true;
        if(s1.isEmpty()) return s2.equals(s3);
        if(s2.isEmpty()) return s1.equals(s3);
        if(s1.length() + s2.length() != length) return false;

        int[][] dp = new int[s2.length()+1][s1.length()+1];
        // 邊界賦值
        for(int i = 1;i < s1.length()+1;i++){
            if(s1.substring(0,i).equals(s3.substring(0,i))){
                dp[0][i] = 1;
            }
        }
        for(int i = 1;i < s2.length()+1;i++){
            if(s2.substring(0,i).equals(s3.substring(0,i))){
                dp[i][0] = 1;
            }
        }
        
        for(int i = 2;i <= length;i++){
            // 遍歷 i 的所有組成(邊界除外)
            for(int j = 1;j < i;j++){
                // 防止越界
                if(s1.length() >= j && i-j <= s2.length()){
                    if(s1.charAt(j-1) == s3.charAt(i-1) && dp[i-j][j-1] == 1){
                        dp[i-j][j] = 1;
                    }
                }
                // 防止越界
                if(s2.length() >= j && i-j <= s1.length()){
                    if(s2.charAt(j-1) == s3.charAt(i-1) && dp[j-1][i-j] == 1){
                        dp[j][i-j] = 1;
                    }
                }
            }
        }
        return dp[s2.length()][s1.length()]==1;
    }
}

 

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